Initial commit (Clean history)
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Utilities for Google Media Downloads and Resumable Uploads.
|
||||
|
||||
This package has some general purposes modules, e.g.
|
||||
:mod:`~google.resumable_media.common`, but the majority of the
|
||||
public interface will be contained in subpackages.
|
||||
|
||||
===========
|
||||
Subpackages
|
||||
===========
|
||||
|
||||
Each subpackage is tailored to a specific transport library:
|
||||
|
||||
* the :mod:`~google.resumable_media.requests` subpackage uses the ``requests``
|
||||
transport library.
|
||||
|
||||
.. _requests: http://docs.python-requests.org/
|
||||
|
||||
==========
|
||||
Installing
|
||||
==========
|
||||
|
||||
To install with `pip`_:
|
||||
|
||||
.. code-block:: console
|
||||
|
||||
$ pip install --upgrade google-resumable-media
|
||||
|
||||
.. _pip: https://pip.pypa.io/
|
||||
"""
|
||||
|
||||
|
||||
from google.resumable_media.common import DataCorruption
|
||||
from google.resumable_media.common import InvalidResponse
|
||||
from google.resumable_media.common import PERMANENT_REDIRECT
|
||||
from google.resumable_media.common import RetryStrategy
|
||||
from google.resumable_media.common import TOO_MANY_REQUESTS
|
||||
from google.resumable_media.common import UPLOAD_CHUNK_SIZE
|
||||
|
||||
|
||||
__all__ = [
|
||||
"DataCorruption",
|
||||
"InvalidResponse",
|
||||
"PERMANENT_REDIRECT",
|
||||
"RetryStrategy",
|
||||
"TOO_MANY_REQUESTS",
|
||||
"UPLOAD_CHUNK_SIZE",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,550 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Virtual bases classes for downloading media from Google APIs."""
|
||||
|
||||
import http.client
|
||||
import re
|
||||
|
||||
from google._async_resumable_media import _helpers
|
||||
from google.resumable_media import common
|
||||
|
||||
|
||||
_CONTENT_RANGE_RE = re.compile(
|
||||
r"bytes (?P<start_byte>\d+)-(?P<end_byte>\d+)/(?P<total_bytes>\d+)",
|
||||
flags=re.IGNORECASE,
|
||||
)
|
||||
_ACCEPTABLE_STATUS_CODES = (http.client.OK, http.client.PARTIAL_CONTENT)
|
||||
_GET = "GET"
|
||||
_ZERO_CONTENT_RANGE_HEADER = "bytes */0"
|
||||
|
||||
|
||||
class DownloadBase(object):
|
||||
"""Base class for download helpers.
|
||||
|
||||
Defines core shared behavior across different download types.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
the downloaded resource can be written to.
|
||||
start (int): The first byte in a range to be downloaded.
|
||||
end (int): The last byte in a range to be downloaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
"""
|
||||
|
||||
def __init__(self, media_url, stream=None, start=None, end=None, headers=None):
|
||||
self.media_url = media_url
|
||||
self._stream = stream
|
||||
self.start = start
|
||||
self.end = end
|
||||
if headers is None:
|
||||
headers = {}
|
||||
self._headers = headers
|
||||
self._finished = False
|
||||
self._retry_strategy = common.RetryStrategy()
|
||||
|
||||
@property
|
||||
def finished(self):
|
||||
"""bool: Flag indicating if the download has completed."""
|
||||
return self._finished
|
||||
|
||||
@staticmethod
|
||||
def _get_status_code(response):
|
||||
"""Access the status code from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
@staticmethod
|
||||
def _get_headers(response):
|
||||
"""Access the headers from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
@staticmethod
|
||||
def _get_body(response):
|
||||
"""Access the response body from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
class Download(DownloadBase):
|
||||
"""Helper to manage downloading a resource from a Google API.
|
||||
|
||||
"Slices" of the resource can be retrieved by specifying a range
|
||||
with ``start`` and / or ``end``. However, in typical usage, neither
|
||||
``start`` nor ``end`` is expected to be provided.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
the downloaded resource can be written to.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, but ``end`` is provided, will download from the
|
||||
beginning to ``end`` of the media.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, but ``start`` is provided, will download from the
|
||||
``start`` to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. The response headers must contain
|
||||
a checksum of the requested type. If the headers lack an
|
||||
appropriate checksum (for instance in the case of transcoded or
|
||||
ranged downloads where the remote service does not know the
|
||||
correct checksum) an INFO-level log will be emitted. Supported
|
||||
values are "md5", "crc32c" and None.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self, media_url, stream=None, start=None, end=None, headers=None, checksum="md5"
|
||||
):
|
||||
super(Download, self).__init__(
|
||||
media_url, stream=stream, start=start, end=end, headers=headers
|
||||
)
|
||||
self.checksum = checksum
|
||||
|
||||
def _prepare_request(self):
|
||||
"""Prepare the contents of an HTTP request.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always GET)
|
||||
* the URL for the request
|
||||
* the body of the request (always :data:`None`)
|
||||
* headers for the request
|
||||
|
||||
Raises:
|
||||
ValueError: If the current :class:`Download` has already
|
||||
finished.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.finished:
|
||||
raise ValueError("A download can only be used once.")
|
||||
|
||||
add_bytes_range(self.start, self.end, self._headers)
|
||||
return _GET, self.media_url, None, self._headers
|
||||
|
||||
def _process_response(self, response):
|
||||
"""Process the response from an HTTP request.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
# Tombstone the current Download so it cannot be used again.
|
||||
self._finished = True
|
||||
_helpers.require_status_code(
|
||||
response, _ACCEPTABLE_STATUS_CODES, self._get_status_code
|
||||
)
|
||||
|
||||
def consume(self, transport, timeout=None):
|
||||
"""Consume the resource to be downloaded.
|
||||
|
||||
If a ``stream`` is attached to this download, then the downloaded
|
||||
resource will be written to the stream.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
class ChunkedDownload(DownloadBase):
|
||||
"""Download a resource in chunks from a Google API.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each
|
||||
request.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
will be used to concatenate chunks of the resource as they are
|
||||
downloaded.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, defaults to ``0``.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, will download to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with each request, e.g. headers for data encryption
|
||||
key headers.
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each request.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``start`` is negative.
|
||||
"""
|
||||
|
||||
def __init__(self, media_url, chunk_size, stream, start=0, end=None, headers=None):
|
||||
if start < 0:
|
||||
raise ValueError(
|
||||
"On a chunked download the starting " "value cannot be negative."
|
||||
)
|
||||
super(ChunkedDownload, self).__init__(
|
||||
media_url, stream=stream, start=start, end=end, headers=headers
|
||||
)
|
||||
self.chunk_size = chunk_size
|
||||
self._bytes_downloaded = 0
|
||||
self._total_bytes = None
|
||||
self._invalid = False
|
||||
|
||||
@property
|
||||
def bytes_downloaded(self):
|
||||
"""int: Number of bytes that have been downloaded."""
|
||||
return self._bytes_downloaded
|
||||
|
||||
@property
|
||||
def total_bytes(self):
|
||||
"""Optional[int]: The total number of bytes to be downloaded."""
|
||||
return self._total_bytes
|
||||
|
||||
@property
|
||||
def invalid(self):
|
||||
"""bool: Indicates if the download is in an invalid state.
|
||||
|
||||
This will occur if a call to :meth:`consume_next_chunk` fails.
|
||||
"""
|
||||
return self._invalid
|
||||
|
||||
def _get_byte_range(self):
|
||||
"""Determines the byte range for the next request.
|
||||
|
||||
Returns:
|
||||
Tuple[int, int]: The pair of begin and end byte for the next
|
||||
chunked request.
|
||||
"""
|
||||
curr_start = self.start + self.bytes_downloaded
|
||||
curr_end = curr_start + self.chunk_size - 1
|
||||
# Make sure ``curr_end`` does not exceed ``end``.
|
||||
if self.end is not None:
|
||||
curr_end = min(curr_end, self.end)
|
||||
# Make sure ``curr_end`` does not exceed ``total_bytes - 1``.
|
||||
if self.total_bytes is not None:
|
||||
curr_end = min(curr_end, self.total_bytes - 1)
|
||||
return curr_start, curr_end
|
||||
|
||||
def _prepare_request(self):
|
||||
"""Prepare the contents of an HTTP request.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
.. note:
|
||||
|
||||
This method will be used multiple times, so ``headers`` will
|
||||
be mutated in between requests. However, we don't make a copy
|
||||
since the same keys are being updated.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always GET)
|
||||
* the URL for the request
|
||||
* the body of the request (always :data:`None`)
|
||||
* headers for the request
|
||||
|
||||
Raises:
|
||||
ValueError: If the current download has finished.
|
||||
ValueError: If the current download is invalid.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.finished:
|
||||
raise ValueError("Download has finished.")
|
||||
if self.invalid:
|
||||
raise ValueError("Download is invalid and cannot be re-used.")
|
||||
|
||||
curr_start, curr_end = self._get_byte_range()
|
||||
add_bytes_range(curr_start, curr_end, self._headers)
|
||||
return _GET, self.media_url, None, self._headers
|
||||
|
||||
def _make_invalid(self):
|
||||
"""Simple setter for ``invalid``.
|
||||
|
||||
This is intended to be passed along as a callback to helpers that
|
||||
raise an exception so they can mark this instance as invalid before
|
||||
raising.
|
||||
"""
|
||||
self._invalid = True
|
||||
|
||||
async def _process_response(self, response):
|
||||
"""Process the response from an HTTP request.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O. This is based on the `sans-I/O`_ philosophy.
|
||||
|
||||
For the time being, this **does require** some form of I/O to write
|
||||
a chunk to ``stream``. However, this will (almost) certainly not be
|
||||
network I/O.
|
||||
|
||||
Updates the current state after consuming a chunk. First,
|
||||
increments ``bytes_downloaded`` by the number of bytes in the
|
||||
``content-length`` header.
|
||||
|
||||
If ``total_bytes`` is already set, this assumes (but does not check)
|
||||
that we already have the correct value and doesn't bother to check
|
||||
that it agrees with the headers.
|
||||
|
||||
We expect the **total** length to be in the ``content-range`` header,
|
||||
but this header is only present on requests which sent the ``range``
|
||||
header. This response header should be of the form
|
||||
``bytes {start}-{end}/{total}`` and ``{end} - {start} + 1``
|
||||
should be the same as the ``Content-Length``.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object (need headers).
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the number
|
||||
of bytes in the body doesn't match the content length header.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
# Verify the response before updating the current instance.
|
||||
if _check_for_zero_content_range(
|
||||
response, self._get_status_code, self._get_headers
|
||||
):
|
||||
self._finished = True
|
||||
return
|
||||
|
||||
_helpers.require_status_code(
|
||||
response,
|
||||
_ACCEPTABLE_STATUS_CODES,
|
||||
self._get_status_code,
|
||||
callback=self._make_invalid,
|
||||
)
|
||||
headers = self._get_headers(response)
|
||||
response_body = await self._get_body(response)
|
||||
|
||||
start_byte, end_byte, total_bytes = get_range_info(
|
||||
response, self._get_headers, callback=self._make_invalid
|
||||
)
|
||||
|
||||
transfer_encoding = headers.get("transfer-encoding")
|
||||
|
||||
if transfer_encoding is None:
|
||||
content_length = _helpers.header_required(
|
||||
response,
|
||||
"content-length",
|
||||
self._get_headers,
|
||||
callback=self._make_invalid,
|
||||
)
|
||||
num_bytes = int(content_length)
|
||||
|
||||
if len(response_body) != num_bytes:
|
||||
self._make_invalid()
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
"Response is different size than content-length",
|
||||
"Expected",
|
||||
num_bytes,
|
||||
"Received",
|
||||
len(response_body),
|
||||
)
|
||||
else:
|
||||
# 'content-length' header not allowed with chunked encoding.
|
||||
num_bytes = end_byte - start_byte + 1
|
||||
|
||||
# First update ``bytes_downloaded``.
|
||||
self._bytes_downloaded += num_bytes
|
||||
# If the end byte is past ``end`` or ``total_bytes - 1`` we are done.
|
||||
if self.end is not None and end_byte >= self.end:
|
||||
self._finished = True
|
||||
elif end_byte >= total_bytes - 1:
|
||||
self._finished = True
|
||||
# NOTE: We only use ``total_bytes`` if not already known.
|
||||
if self.total_bytes is None:
|
||||
self._total_bytes = total_bytes
|
||||
# Write the response body to the stream.
|
||||
self._stream.write(response_body)
|
||||
|
||||
def consume_next_chunk(self, transport, timeout=None):
|
||||
"""Consume the next chunk of the resource to be downloaded.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
def add_bytes_range(start, end, headers):
|
||||
"""Add a bytes range to a header dictionary.
|
||||
|
||||
Some possible inputs and the corresponding bytes ranges::
|
||||
|
||||
>>> headers = {}
|
||||
>>> add_bytes_range(None, None, headers)
|
||||
>>> headers
|
||||
{}
|
||||
>>> add_bytes_range(500, 999, headers)
|
||||
>>> headers['range']
|
||||
'bytes=500-999'
|
||||
>>> add_bytes_range(None, 499, headers)
|
||||
>>> headers['range']
|
||||
'bytes=0-499'
|
||||
>>> add_bytes_range(-500, None, headers)
|
||||
>>> headers['range']
|
||||
'bytes=-500'
|
||||
>>> add_bytes_range(9500, None, headers)
|
||||
>>> headers['range']
|
||||
'bytes=9500-'
|
||||
|
||||
Args:
|
||||
start (Optional[int]): The first byte in a range. Can be zero,
|
||||
positive, negative or :data:`None`.
|
||||
end (Optional[int]): The last byte in a range. Assumed to be
|
||||
positive.
|
||||
headers (Mapping[str, str]): A headers mapping which can have the
|
||||
bytes range added if at least one of ``start`` or ``end``
|
||||
is not :data:`None`.
|
||||
"""
|
||||
if start is None:
|
||||
if end is None:
|
||||
# No range to add.
|
||||
return
|
||||
else:
|
||||
# NOTE: This assumes ``end`` is non-negative.
|
||||
bytes_range = "0-{:d}".format(end)
|
||||
else:
|
||||
if end is None:
|
||||
if start < 0:
|
||||
bytes_range = "{:d}".format(start)
|
||||
else:
|
||||
bytes_range = "{:d}-".format(start)
|
||||
else:
|
||||
# NOTE: This is invalid if ``start < 0``.
|
||||
bytes_range = "{:d}-{:d}".format(start, end)
|
||||
|
||||
headers[_helpers.RANGE_HEADER] = "bytes=" + bytes_range
|
||||
|
||||
|
||||
def get_range_info(response, get_headers, callback=_helpers.do_nothing):
|
||||
"""Get the start, end and total bytes from a content range header.
|
||||
|
||||
Args:
|
||||
response (object): An HTTP response object.
|
||||
get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers
|
||||
from an HTTP response.
|
||||
callback (Optional[Callable]): A callback that takes no arguments,
|
||||
to be executed when an exception is being raised.
|
||||
|
||||
Returns:
|
||||
Tuple[int, int, int]: The start byte, end byte and total bytes.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the
|
||||
``Content-Range`` header is not of the form
|
||||
``bytes {start}-{end}/{total}``.
|
||||
"""
|
||||
content_range = _helpers.header_required(
|
||||
response, _helpers.CONTENT_RANGE_HEADER, get_headers, callback=callback
|
||||
)
|
||||
match = _CONTENT_RANGE_RE.match(content_range)
|
||||
if match is None:
|
||||
callback()
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
"Unexpected content-range header",
|
||||
content_range,
|
||||
'Expected to be of the form "bytes {start}-{end}/{total}"',
|
||||
)
|
||||
|
||||
return (
|
||||
int(match.group("start_byte")),
|
||||
int(match.group("end_byte")),
|
||||
int(match.group("total_bytes")),
|
||||
)
|
||||
|
||||
|
||||
def _check_for_zero_content_range(response, get_status_code, get_headers):
|
||||
"""Validate if response status code is 416 and content range is zero.
|
||||
|
||||
This is the special case for handling zero bytes files.
|
||||
|
||||
Args:
|
||||
response (object): An HTTP response object.
|
||||
get_status_code (Callable[Any, int]): Helper to get a status code
|
||||
from a response.
|
||||
get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers
|
||||
from an HTTP response.
|
||||
|
||||
Returns:
|
||||
bool: True if content range total bytes is zero, false otherwise.
|
||||
"""
|
||||
if get_status_code(response) == http.client.REQUESTED_RANGE_NOT_SATISFIABLE:
|
||||
content_range = _helpers.header_required(
|
||||
response,
|
||||
_helpers.CONTENT_RANGE_HEADER,
|
||||
get_headers,
|
||||
callback=_helpers.do_nothing,
|
||||
)
|
||||
if content_range == _ZERO_CONTENT_RANGE_HEADER:
|
||||
return True
|
||||
return False
|
||||
@@ -0,0 +1,197 @@
|
||||
# Copyright 2020 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Shared utilities used by both downloads and uploads."""
|
||||
|
||||
import logging
|
||||
import random
|
||||
import time
|
||||
|
||||
|
||||
from google.resumable_media import common
|
||||
|
||||
|
||||
RANGE_HEADER = "range"
|
||||
CONTENT_RANGE_HEADER = "content-range"
|
||||
|
||||
_SLOW_CRC32C_WARNING = (
|
||||
"Currently using crcmod in pure python form. This is a slow "
|
||||
"implementation. Python 3 has a faster implementation, `google-crc32c`, "
|
||||
"which will be used if it is installed."
|
||||
)
|
||||
_HASH_HEADER = "x-goog-hash"
|
||||
_MISSING_CHECKSUM = """\
|
||||
No {checksum_type} checksum was returned from the service while downloading {}
|
||||
(which happens for composite objects), so client-side content integrity
|
||||
checking is not being performed."""
|
||||
_LOGGER = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def do_nothing():
|
||||
"""Simple default callback."""
|
||||
|
||||
|
||||
def header_required(response, name, get_headers, callback=do_nothing):
|
||||
"""Checks that a specific header is in a headers dictionary.
|
||||
|
||||
Args:
|
||||
response (object): An HTTP response object, expected to have a
|
||||
``headers`` attribute that is a ``Mapping[str, str]``.
|
||||
name (str): The name of a required header.
|
||||
get_headers (Callable[Any, Mapping[str, str]]): Helper to get headers
|
||||
from an HTTP response.
|
||||
callback (Optional[Callable]): A callback that takes no arguments,
|
||||
to be executed when an exception is being raised.
|
||||
|
||||
Returns:
|
||||
str: The desired header.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the header
|
||||
is missing.
|
||||
"""
|
||||
headers = get_headers(response)
|
||||
if name not in headers:
|
||||
callback()
|
||||
raise common.InvalidResponse(
|
||||
response, "Response headers must contain header", name
|
||||
)
|
||||
|
||||
return headers[name]
|
||||
|
||||
|
||||
def require_status_code(response, status_codes, get_status_code, callback=do_nothing):
|
||||
"""Require a response has a status code among a list.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
status_codes (tuple): The acceptable status codes.
|
||||
get_status_code (Callable[Any, int]): Helper to get a status code
|
||||
from a response.
|
||||
callback (Optional[Callable]): A callback that takes no arguments,
|
||||
to be executed when an exception is being raised.
|
||||
|
||||
Returns:
|
||||
int: The status code.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the status code
|
||||
is not one of the values in ``status_codes``.
|
||||
"""
|
||||
status_code = get_status_code(response)
|
||||
if status_code not in status_codes:
|
||||
callback()
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
"Request failed with status code",
|
||||
status_code,
|
||||
"Expected one of",
|
||||
*status_codes
|
||||
)
|
||||
return status_code
|
||||
|
||||
|
||||
def calculate_retry_wait(base_wait, max_sleep):
|
||||
"""Calculate the amount of time to wait before a retry attempt.
|
||||
|
||||
Wait time grows exponentially with the number of attempts, until
|
||||
``max_sleep``.
|
||||
|
||||
A random amount of jitter (between 0 and 1 seconds) is added to spread out
|
||||
retry attempts from different clients.
|
||||
|
||||
Args:
|
||||
base_wait (float): The "base" wait time (i.e. without any jitter)
|
||||
that will be doubled until it reaches the maximum sleep.
|
||||
max_sleep (float): Maximum value that a sleep time is allowed to be.
|
||||
|
||||
Returns:
|
||||
Tuple[float, float]: The new base wait time as well as the wait time
|
||||
to be applied (with a random amount of jitter between 0 and 1 seconds
|
||||
added).
|
||||
"""
|
||||
new_base_wait = 2.0 * base_wait
|
||||
if new_base_wait > max_sleep:
|
||||
new_base_wait = max_sleep
|
||||
|
||||
jitter_ms = random.randint(0, 1000)
|
||||
return new_base_wait, new_base_wait + 0.001 * jitter_ms
|
||||
|
||||
|
||||
async def wait_and_retry(func, get_status_code, retry_strategy):
|
||||
"""Attempts to retry a call to ``func`` until success.
|
||||
|
||||
Expects ``func`` to return an HTTP response and uses ``get_status_code``
|
||||
to check if the response is retry-able.
|
||||
|
||||
Will retry until :meth:`~.RetryStrategy.retry_allowed` (on the current
|
||||
``retry_strategy``) returns :data:`False`. Uses
|
||||
:func:`calculate_retry_wait` to double the wait time (with jitter) after
|
||||
each attempt.
|
||||
|
||||
Args:
|
||||
func (Callable): A callable that takes no arguments and produces
|
||||
an HTTP response which will be checked as retry-able.
|
||||
get_status_code (Callable[Any, int]): Helper to get a status code
|
||||
from a response.
|
||||
retry_strategy (~google.resumable_media.common.RetryStrategy): The
|
||||
strategy to use if the request fails and must be retried.
|
||||
|
||||
Returns:
|
||||
object: The return value of ``func``.
|
||||
"""
|
||||
|
||||
total_sleep = 0.0
|
||||
num_retries = 0
|
||||
base_wait = 0.5 # When doubled will give 1.0
|
||||
|
||||
while True: # return on success or when retries exhausted.
|
||||
error = None
|
||||
try:
|
||||
response = await func()
|
||||
except ConnectionError as e:
|
||||
error = e
|
||||
else:
|
||||
if get_status_code(response) not in common.RETRYABLE:
|
||||
return response
|
||||
|
||||
if not retry_strategy.retry_allowed(total_sleep, num_retries):
|
||||
# Retries are exhausted and no acceptable response was received. Raise the
|
||||
# retriable_error or return the unacceptable response.
|
||||
if error:
|
||||
raise error
|
||||
|
||||
return response
|
||||
|
||||
base_wait, wait_time = calculate_retry_wait(base_wait, retry_strategy.max_sleep)
|
||||
|
||||
num_retries += 1
|
||||
total_sleep += wait_time
|
||||
time.sleep(wait_time)
|
||||
|
||||
|
||||
class _DoNothingHash(object):
|
||||
"""Do-nothing hash object.
|
||||
|
||||
Intended as a stand-in for ``hashlib.md5`` or a crc32c checksum
|
||||
implementation in cases where it isn't necessary to compute the hash.
|
||||
"""
|
||||
|
||||
def update(self, unused_chunk):
|
||||
"""Do-nothing ``update`` method.
|
||||
|
||||
Intended to match the interface of ``hashlib.md5`` and other checksums.
|
||||
Args:
|
||||
unused_chunk (bytes): A chunk of data.
|
||||
"""
|
||||
@@ -0,0 +1,976 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Virtual bases classes for uploading media via Google APIs.
|
||||
|
||||
Supported here are:
|
||||
|
||||
* simple (media) uploads
|
||||
* multipart uploads that contain both metadata and a small file as payload
|
||||
* resumable uploads (with metadata as well)
|
||||
"""
|
||||
|
||||
import http.client
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import sys
|
||||
|
||||
from google import _async_resumable_media
|
||||
from google._async_resumable_media import _helpers
|
||||
from google.resumable_media import _helpers as sync_helpers
|
||||
from google.resumable_media import _upload as sync_upload
|
||||
from google.resumable_media import common
|
||||
|
||||
|
||||
from google.resumable_media._upload import (
|
||||
_CONTENT_TYPE_HEADER,
|
||||
_CONTENT_RANGE_TEMPLATE,
|
||||
_RANGE_UNKNOWN_TEMPLATE,
|
||||
_EMPTY_RANGE_TEMPLATE,
|
||||
_BOUNDARY_FORMAT,
|
||||
_MULTIPART_SEP,
|
||||
_CRLF,
|
||||
_MULTIPART_BEGIN,
|
||||
_RELATED_HEADER,
|
||||
_BYTES_RANGE_RE,
|
||||
_STREAM_ERROR_TEMPLATE,
|
||||
_POST,
|
||||
_PUT,
|
||||
_UPLOAD_CHECKSUM_MISMATCH_MESSAGE,
|
||||
_UPLOAD_METADATA_NO_APPROPRIATE_CHECKSUM_MESSAGE,
|
||||
)
|
||||
|
||||
|
||||
class UploadBase(object):
|
||||
"""Base class for upload helpers.
|
||||
|
||||
Defines core shared behavior across different upload types.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
"""
|
||||
|
||||
def __init__(self, upload_url, headers=None):
|
||||
self.upload_url = upload_url
|
||||
if headers is None:
|
||||
headers = {}
|
||||
self._headers = headers
|
||||
self._finished = False
|
||||
self._retry_strategy = common.RetryStrategy()
|
||||
|
||||
@property
|
||||
def finished(self):
|
||||
"""bool: Flag indicating if the upload has completed."""
|
||||
return self._finished
|
||||
|
||||
def _process_response(self, response):
|
||||
"""Process the response from an HTTP request.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is not 200.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
# Tombstone the current upload so it cannot be used again (in either
|
||||
# failure or success).
|
||||
self._finished = True
|
||||
_helpers.require_status_code(response, (http.client.OK,), self._get_status_code)
|
||||
|
||||
@staticmethod
|
||||
def _get_status_code(response):
|
||||
"""Access the status code from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
@staticmethod
|
||||
def _get_headers(response):
|
||||
"""Access the headers from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
@staticmethod
|
||||
def _get_body(response):
|
||||
"""Access the response body from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
class SimpleUpload(UploadBase):
|
||||
"""Upload a resource to a Google API.
|
||||
|
||||
A **simple** media upload sends no metadata and completes the upload
|
||||
in a single request.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
"""
|
||||
|
||||
def _prepare_request(self, data, content_type):
|
||||
"""Prepare the contents of an HTTP request.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
.. note:
|
||||
|
||||
This method will be used only once, so ``headers`` will be
|
||||
mutated by having a new key added to it.
|
||||
|
||||
Args:
|
||||
data (bytes): The resource content to be uploaded.
|
||||
content_type (str): The content type for the request.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, bytes, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always POST)
|
||||
* the URL for the request
|
||||
* the body of the request
|
||||
* headers for the request
|
||||
|
||||
Raises:
|
||||
ValueError: If the current upload has already finished.
|
||||
TypeError: If ``data`` isn't bytes.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.finished:
|
||||
raise ValueError("An upload can only be used once.")
|
||||
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("`data` must be bytes, received", type(data))
|
||||
self._headers[_CONTENT_TYPE_HEADER] = content_type
|
||||
return _POST, self.upload_url, data, self._headers
|
||||
|
||||
def transmit(self, transport, data, content_type, timeout=None):
|
||||
"""Transmit the resource to be uploaded.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
data (bytes): The resource content to be uploaded.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
class MultipartUpload(UploadBase):
|
||||
"""Upload a resource with metadata to a Google API.
|
||||
|
||||
A **multipart** upload sends both metadata and the resource in a single
|
||||
(multipart) request.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. The request metadata will be amended
|
||||
to include the computed value. Using this option will override a
|
||||
manually-set checksum value. Supported values are "md5", "crc32c"
|
||||
and None. The default is None.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
"""
|
||||
|
||||
def __init__(self, upload_url, headers=None, checksum=None):
|
||||
super(MultipartUpload, self).__init__(upload_url, headers=headers)
|
||||
self._checksum_type = checksum
|
||||
|
||||
def _prepare_request(self, data, metadata, content_type):
|
||||
"""Prepare the contents of an HTTP request.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
.. note:
|
||||
|
||||
This method will be used only once, so ``headers`` will be
|
||||
mutated by having a new key added to it.
|
||||
|
||||
Args:
|
||||
data (bytes): The resource content to be uploaded.
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, bytes, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always POST)
|
||||
* the URL for the request
|
||||
* the body of the request
|
||||
* headers for the request
|
||||
|
||||
Raises:
|
||||
ValueError: If the current upload has already finished.
|
||||
TypeError: If ``data`` isn't bytes.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.finished:
|
||||
raise ValueError("An upload can only be used once.")
|
||||
|
||||
if not isinstance(data, bytes):
|
||||
raise TypeError("`data` must be bytes, received", type(data))
|
||||
|
||||
checksum_object = sync_helpers._get_checksum_object(self._checksum_type)
|
||||
|
||||
if checksum_object is not None:
|
||||
checksum_object.update(data)
|
||||
actual_checksum = sync_helpers.prepare_checksum_digest(
|
||||
checksum_object.digest()
|
||||
)
|
||||
metadata_key = sync_helpers._get_metadata_key(self._checksum_type)
|
||||
metadata[metadata_key] = actual_checksum
|
||||
|
||||
content, multipart_boundary = construct_multipart_request(
|
||||
data, metadata, content_type
|
||||
)
|
||||
multipart_content_type = _RELATED_HEADER + multipart_boundary + b'"'
|
||||
|
||||
self._headers[_CONTENT_TYPE_HEADER] = multipart_content_type
|
||||
|
||||
return _POST, self.upload_url, content, self._headers
|
||||
|
||||
def transmit(self, transport, data, metadata, content_type, timeout=None):
|
||||
"""Transmit the resource to be uploaded.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
data (bytes): The resource content to be uploaded.
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
class ResumableUpload(UploadBase, sync_upload.ResumableUpload):
|
||||
"""Initiate and fulfill a resumable upload to a Google API.
|
||||
|
||||
A **resumable** upload sends an initial request with the resource metadata
|
||||
and then gets assigned an upload ID / upload URL to send bytes to.
|
||||
Using the upload URL, the upload is then done in chunks (determined by
|
||||
the user) until all bytes have been uploaded.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the resumable upload will be initiated.
|
||||
chunk_size (int): The size of each chunk used to upload the resource.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the :meth:`initiate` request, e.g. headers for
|
||||
encrypted data. These **will not** be sent with
|
||||
:meth:`transmit_next_chunk` or :meth:`recover` requests.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. After the upload is complete, the
|
||||
server-computed checksum of the resulting object will be read
|
||||
and google.resumable_media.common.DataCorruption will be raised on
|
||||
a mismatch. The corrupted file will not be deleted from the remote
|
||||
host automatically. Supported values are "md5", "crc32c" and None.
|
||||
The default is None.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``chunk_size`` is not a multiple of
|
||||
:data:`.UPLOAD_CHUNK_SIZE`.
|
||||
"""
|
||||
|
||||
def __init__(self, upload_url, chunk_size, checksum=None, headers=None):
|
||||
super(ResumableUpload, self).__init__(upload_url, headers=headers)
|
||||
if chunk_size % _async_resumable_media.UPLOAD_CHUNK_SIZE != 0:
|
||||
raise ValueError(
|
||||
"{} KB must divide chunk size".format(
|
||||
_async_resumable_media.UPLOAD_CHUNK_SIZE / 1024
|
||||
)
|
||||
)
|
||||
self._chunk_size = chunk_size
|
||||
self._stream = None
|
||||
self._content_type = None
|
||||
self._bytes_uploaded = 0
|
||||
self._bytes_checksummed = 0
|
||||
self._checksum_type = checksum
|
||||
self._checksum_object = None
|
||||
self._total_bytes = None
|
||||
self._resumable_url = None
|
||||
self._invalid = False
|
||||
|
||||
@property
|
||||
def invalid(self):
|
||||
"""bool: Indicates if the upload is in an invalid state.
|
||||
|
||||
This will occur if a call to :meth:`transmit_next_chunk` fails.
|
||||
To recover from such a failure, call :meth:`recover`.
|
||||
"""
|
||||
return self._invalid
|
||||
|
||||
@property
|
||||
def chunk_size(self):
|
||||
"""int: The size of each chunk used to upload the resource."""
|
||||
return self._chunk_size
|
||||
|
||||
@property
|
||||
def resumable_url(self):
|
||||
"""Optional[str]: The URL of the in-progress resumable upload."""
|
||||
return self._resumable_url
|
||||
|
||||
@property
|
||||
def bytes_uploaded(self):
|
||||
"""int: Number of bytes that have been uploaded."""
|
||||
return self._bytes_uploaded
|
||||
|
||||
@property
|
||||
def total_bytes(self):
|
||||
"""Optional[int]: The total number of bytes to be uploaded.
|
||||
|
||||
If this upload is initiated (via :meth:`initiate`) with
|
||||
``stream_final=True``, this value will be populated based on the size
|
||||
of the ``stream`` being uploaded. (By default ``stream_final=True``.)
|
||||
|
||||
If this upload is initiated with ``stream_final=False``,
|
||||
:attr:`total_bytes` will be :data:`None` since it cannot be
|
||||
determined from the stream.
|
||||
"""
|
||||
return self._total_bytes
|
||||
|
||||
def _prepare_initiate_request(
|
||||
self, stream, metadata, content_type, total_bytes=None, stream_final=True
|
||||
):
|
||||
"""Prepare the contents of HTTP request to initiate upload.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Args:
|
||||
stream (IO[bytes]): The stream (i.e. file-like object) that will
|
||||
be uploaded. The stream **must** be at the beginning (i.e.
|
||||
``stream.tell() == 0``).
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
total_bytes (Optional[int]): The total number of bytes to be
|
||||
uploaded. If specified, the upload size **will not** be
|
||||
determined from the stream (even if ``stream_final=True``).
|
||||
stream_final (Optional[bool]): Indicates if the ``stream`` is
|
||||
"final" (i.e. no more bytes will be added to it). In this case
|
||||
we determine the upload size from the size of the stream. If
|
||||
``total_bytes`` is passed, this argument will be ignored.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, bytes, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always POST)
|
||||
* the URL for the request
|
||||
* the body of the request
|
||||
* headers for the request
|
||||
|
||||
Raises:
|
||||
ValueError: If the current upload has already been initiated.
|
||||
ValueError: If ``stream`` is not at the beginning.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.resumable_url is not None:
|
||||
raise ValueError("This upload has already been initiated.")
|
||||
if stream.tell() != 0:
|
||||
raise ValueError("Stream must be at beginning.")
|
||||
|
||||
self._stream = stream
|
||||
self._content_type = content_type
|
||||
headers = {
|
||||
_CONTENT_TYPE_HEADER: "application/json; charset=UTF-8",
|
||||
"x-upload-content-type": content_type,
|
||||
}
|
||||
# Set the total bytes if possible.
|
||||
if total_bytes is not None:
|
||||
self._total_bytes = total_bytes
|
||||
elif stream_final:
|
||||
self._total_bytes = get_total_bytes(stream)
|
||||
# Add the total bytes to the headers if set.
|
||||
if self._total_bytes is not None:
|
||||
content_length = "{:d}".format(self._total_bytes)
|
||||
headers["x-upload-content-length"] = content_length
|
||||
|
||||
headers.update(self._headers)
|
||||
payload = json.dumps(metadata).encode("utf-8")
|
||||
return _POST, self.upload_url, payload, headers
|
||||
|
||||
def _process_initiate_response(self, response):
|
||||
"""Process the response from an HTTP request that initiated upload.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
This method takes the URL from the ``Location`` header and stores it
|
||||
for future use. Within that URL, we assume the ``upload_id`` query
|
||||
parameter has been included, but we do not check.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object (need headers).
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
_helpers.require_status_code(
|
||||
response,
|
||||
(http.client.OK,),
|
||||
self._get_status_code,
|
||||
callback=self._make_invalid,
|
||||
)
|
||||
self._resumable_url = _helpers.header_required(
|
||||
response, "location", self._get_headers
|
||||
)
|
||||
|
||||
def initiate(
|
||||
self,
|
||||
transport,
|
||||
stream,
|
||||
metadata,
|
||||
content_type,
|
||||
total_bytes=None,
|
||||
stream_final=True,
|
||||
timeout=None,
|
||||
):
|
||||
"""Initiate a resumable upload.
|
||||
|
||||
By default, this method assumes your ``stream`` is in a "final"
|
||||
state ready to transmit. However, ``stream_final=False`` can be used
|
||||
to indicate that the size of the resource is not known. This can happen
|
||||
if bytes are being dynamically fed into ``stream``, e.g. if the stream
|
||||
is attached to application logs.
|
||||
|
||||
If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be
|
||||
read from the stream every time :meth:`transmit_next_chunk` is called.
|
||||
If one of those reads produces strictly fewer bites than the chunk
|
||||
size, the upload will be concluded.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
stream (IO[bytes]): The stream (i.e. file-like object) that will
|
||||
be uploaded. The stream **must** be at the beginning (i.e.
|
||||
``stream.tell() == 0``).
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
total_bytes (Optional[int]): The total number of bytes to be
|
||||
uploaded. If specified, the upload size **will not** be
|
||||
determined from the stream (even if ``stream_final=True``).
|
||||
stream_final (Optional[bool]): Indicates if the ``stream`` is
|
||||
"final" (i.e. no more bytes will be added to it). In this case
|
||||
we determine the upload size from the size of the stream. If
|
||||
``total_bytes`` is passed, this argument will be ignored.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
def _prepare_request(self):
|
||||
"""Prepare the contents of HTTP request to upload a chunk.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O. This is based on the `sans-I/O`_ philosophy.
|
||||
|
||||
For the time being, this **does require** some form of I/O to read
|
||||
a chunk from ``stream`` (via :func:`get_next_chunk`). However, this
|
||||
will (almost) certainly not be network I/O.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, bytes, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always PUT)
|
||||
* the URL for the request
|
||||
* the body of the request
|
||||
* headers for the request
|
||||
|
||||
The headers **do not** incorporate the ``_headers`` on the
|
||||
current instance.
|
||||
|
||||
Raises:
|
||||
ValueError: If the current upload has finished.
|
||||
ValueError: If the current upload is in an invalid state.
|
||||
ValueError: If the current upload has not been initiated.
|
||||
ValueError: If the location in the stream (i.e. ``stream.tell()``)
|
||||
does not agree with ``bytes_uploaded``.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if self.finished:
|
||||
raise ValueError("Upload has finished.")
|
||||
if self.invalid:
|
||||
raise ValueError(
|
||||
"Upload is in an invalid state. To recover call `recover()`."
|
||||
)
|
||||
if self.resumable_url is None:
|
||||
raise ValueError(
|
||||
"This upload has not been initiated. Please call "
|
||||
"initiate() before beginning to transmit chunks."
|
||||
)
|
||||
|
||||
start_byte, payload, content_range = get_next_chunk(
|
||||
self._stream, self._chunk_size, self._total_bytes
|
||||
)
|
||||
if start_byte != self.bytes_uploaded:
|
||||
msg = _STREAM_ERROR_TEMPLATE.format(start_byte, self.bytes_uploaded)
|
||||
raise ValueError(msg)
|
||||
|
||||
self._update_checksum(start_byte, payload)
|
||||
|
||||
headers = {
|
||||
_CONTENT_TYPE_HEADER: self._content_type,
|
||||
_helpers.CONTENT_RANGE_HEADER: content_range,
|
||||
}
|
||||
return _PUT, self.resumable_url, payload, headers
|
||||
|
||||
def _make_invalid(self):
|
||||
"""Simple setter for ``invalid``.
|
||||
|
||||
This is intended to be passed along as a callback to helpers that
|
||||
raise an exception so they can mark this instance as invalid before
|
||||
raising.
|
||||
"""
|
||||
self._invalid = True
|
||||
|
||||
async def _process_resumable_response(self, response, bytes_sent):
|
||||
"""Process the response from an HTTP request.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
bytes_sent (int): The number of bytes sent in the request that
|
||||
``response`` was returned for.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is 308 and the ``range`` header is not of the form
|
||||
``bytes 0-{end}``.
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is not 200 or 308.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
status_code = _helpers.require_status_code(
|
||||
response,
|
||||
(http.client.OK, http.client.PERMANENT_REDIRECT),
|
||||
self._get_status_code,
|
||||
callback=self._make_invalid,
|
||||
)
|
||||
if status_code == http.client.OK:
|
||||
# NOTE: We use the "local" information of ``bytes_sent`` to update
|
||||
# ``bytes_uploaded``, but do not verify this against other
|
||||
# state. However, there may be some other information:
|
||||
#
|
||||
# * a ``size`` key in JSON response body
|
||||
# * the ``total_bytes`` attribute (if set)
|
||||
# * ``stream.tell()`` (relying on fact that ``initiate()``
|
||||
# requires stream to be at the beginning)
|
||||
self._bytes_uploaded = self._bytes_uploaded + bytes_sent
|
||||
# Tombstone the current upload so it cannot be used again.
|
||||
self._finished = True
|
||||
# Validate the checksum. This can raise an exception on failure.
|
||||
await self._validate_checksum(response)
|
||||
else:
|
||||
bytes_range = _helpers.header_required(
|
||||
response,
|
||||
_helpers.RANGE_HEADER,
|
||||
self._get_headers,
|
||||
callback=self._make_invalid,
|
||||
)
|
||||
match = _BYTES_RANGE_RE.match(bytes_range)
|
||||
if match is None:
|
||||
self._make_invalid()
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
'Unexpected "range" header',
|
||||
bytes_range,
|
||||
'Expected to be of the form "bytes=0-{end}"',
|
||||
)
|
||||
self._bytes_uploaded = int(match.group("end_byte")) + 1
|
||||
|
||||
async def _validate_checksum(self, response):
|
||||
"""Check the computed checksum, if any, against the response headers.
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
Raises:
|
||||
~google.resumable_media.common.DataCorruption: If the checksum
|
||||
computed locally and the checksum reported by the remote host do
|
||||
not match.
|
||||
"""
|
||||
if self._checksum_type is None:
|
||||
return
|
||||
metadata_key = sync_helpers._get_metadata_key(self._checksum_type)
|
||||
metadata = await response.json()
|
||||
remote_checksum = metadata.get(metadata_key)
|
||||
if remote_checksum is None:
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
_UPLOAD_METADATA_NO_APPROPRIATE_CHECKSUM_MESSAGE.format(metadata_key),
|
||||
self._get_headers(response),
|
||||
)
|
||||
local_checksum = sync_helpers.prepare_checksum_digest(
|
||||
self._checksum_object.digest()
|
||||
)
|
||||
if local_checksum != remote_checksum:
|
||||
raise common.DataCorruption(
|
||||
response,
|
||||
_UPLOAD_CHECKSUM_MISMATCH_MESSAGE.format(
|
||||
self._checksum_type.upper(), local_checksum, remote_checksum
|
||||
),
|
||||
)
|
||||
|
||||
def transmit_next_chunk(self, transport, timeout=None):
|
||||
"""Transmit the next chunk of the resource to be uploaded.
|
||||
|
||||
If the current upload was initiated with ``stream_final=False``,
|
||||
this method will dynamically determine if the upload has completed.
|
||||
The upload will be considered complete if the stream produces
|
||||
fewer than :attr:`chunk_size` bytes when a chunk is read from it.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
def _prepare_recover_request(self):
|
||||
"""Prepare the contents of HTTP request to recover from failure.
|
||||
|
||||
This is everything that must be done before a request that doesn't
|
||||
require network I/O. This is based on the `sans-I/O`_ philosophy.
|
||||
|
||||
We assume that the :attr:`resumable_url` is set (i.e. the only way
|
||||
the upload can end up :attr:`invalid` is if it has been initiated.
|
||||
|
||||
Returns:
|
||||
Tuple[str, str, NoneType, Mapping[str, str]]: The quadruple
|
||||
|
||||
* HTTP verb for the request (always PUT)
|
||||
* the URL for the request
|
||||
* the body of the request (always :data:`None`)
|
||||
* headers for the request
|
||||
|
||||
The headers **do not** incorporate the ``_headers`` on the
|
||||
current instance.
|
||||
|
||||
Raises:
|
||||
ValueError: If the current upload is not in an invalid state.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
if not self.invalid:
|
||||
raise ValueError("Upload is not in invalid state, no need to recover.")
|
||||
|
||||
headers = {_helpers.CONTENT_RANGE_HEADER: "bytes */*"}
|
||||
return _PUT, self.resumable_url, None, headers
|
||||
|
||||
def _process_recover_response(self, response):
|
||||
"""Process the response from an HTTP request to recover from failure.
|
||||
|
||||
This is everything that must be done after a request that doesn't
|
||||
require network I/O (or other I/O). This is based on the `sans-I/O`_
|
||||
philosophy.
|
||||
|
||||
Args:
|
||||
response (object): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is not 308.
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is 308 and the ``range`` header is not of the form
|
||||
``bytes 0-{end}``.
|
||||
|
||||
.. _sans-I/O: https://sans-io.readthedocs.io/
|
||||
"""
|
||||
_helpers.require_status_code(
|
||||
response,
|
||||
(http.client.PERMANENT_REDIRECT,),
|
||||
self._get_status_code,
|
||||
)
|
||||
headers = self._get_headers(response)
|
||||
if _helpers.RANGE_HEADER in headers:
|
||||
bytes_range = headers[_helpers.RANGE_HEADER]
|
||||
match = _BYTES_RANGE_RE.match(bytes_range)
|
||||
if match is None:
|
||||
raise common.InvalidResponse(
|
||||
response,
|
||||
'Unexpected "range" header',
|
||||
bytes_range,
|
||||
'Expected to be of the form "bytes=0-{end}"',
|
||||
)
|
||||
self._bytes_uploaded = int(match.group("end_byte")) + 1
|
||||
else:
|
||||
# In this case, the upload has not "begun".
|
||||
self._bytes_uploaded = 0
|
||||
|
||||
self._stream.seek(self._bytes_uploaded)
|
||||
self._invalid = False
|
||||
|
||||
def recover(self, transport):
|
||||
"""Recover from a failure.
|
||||
|
||||
This method should be used when a :class:`ResumableUpload` is in an
|
||||
:attr:`~ResumableUpload.invalid` state due to a request failure.
|
||||
|
||||
This will verify the progress with the server and make sure the
|
||||
current upload is in a valid state before :meth:`transmit_next_chunk`
|
||||
can be used again.
|
||||
|
||||
Args:
|
||||
transport (object): An object which can make authenticated
|
||||
requests.
|
||||
|
||||
Raises:
|
||||
NotImplementedError: Always, since virtual.
|
||||
"""
|
||||
raise NotImplementedError("This implementation is virtual.")
|
||||
|
||||
|
||||
def get_boundary():
|
||||
"""Get a random boundary for a multipart request.
|
||||
|
||||
Returns:
|
||||
bytes: The boundary used to separate parts of a multipart request.
|
||||
"""
|
||||
random_int = random.randrange(sys.maxsize)
|
||||
boundary = _BOUNDARY_FORMAT.format(random_int)
|
||||
# NOTE: Neither % formatting nor .format() are available for byte strings
|
||||
# in Python 3.4, so we must use unicode strings as templates.
|
||||
return boundary.encode("utf-8")
|
||||
|
||||
|
||||
def construct_multipart_request(data, metadata, content_type):
|
||||
"""Construct a multipart request body.
|
||||
|
||||
Args:
|
||||
data (bytes): The resource content (UTF-8 encoded as bytes)
|
||||
to be uploaded.
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
|
||||
Returns:
|
||||
Tuple[bytes, bytes]: The multipart request body and the boundary used
|
||||
between each part.
|
||||
"""
|
||||
multipart_boundary = get_boundary()
|
||||
json_bytes = json.dumps(metadata).encode("utf-8")
|
||||
content_type = content_type.encode("utf-8")
|
||||
# Combine the two parts into a multipart payload.
|
||||
# NOTE: We'd prefer a bytes template but are restricted by Python 3.4.
|
||||
boundary_sep = _MULTIPART_SEP + multipart_boundary
|
||||
content = (
|
||||
boundary_sep
|
||||
+ _MULTIPART_BEGIN
|
||||
+ json_bytes
|
||||
+ _CRLF
|
||||
+ boundary_sep
|
||||
+ _CRLF
|
||||
+ b"content-type: "
|
||||
+ content_type
|
||||
+ _CRLF
|
||||
+ _CRLF
|
||||
+ data # Empty line between headers and body.
|
||||
+ _CRLF
|
||||
+ boundary_sep
|
||||
+ _MULTIPART_SEP
|
||||
)
|
||||
|
||||
return content, multipart_boundary
|
||||
|
||||
|
||||
def get_total_bytes(stream):
|
||||
"""Determine the total number of bytes in a stream.
|
||||
|
||||
Args:
|
||||
stream (IO[bytes]): The stream (i.e. file-like object).
|
||||
|
||||
Returns:
|
||||
int: The number of bytes.
|
||||
"""
|
||||
current_position = stream.tell()
|
||||
# NOTE: ``.seek()`` **should** return the same value that ``.tell()``
|
||||
# returns, but in Python 2, ``file`` objects do not.
|
||||
stream.seek(0, os.SEEK_END)
|
||||
end_position = stream.tell()
|
||||
# Go back to the initial position.
|
||||
stream.seek(current_position)
|
||||
|
||||
return end_position
|
||||
|
||||
|
||||
def get_next_chunk(stream, chunk_size, total_bytes):
|
||||
"""Get a chunk from an I/O stream.
|
||||
|
||||
The ``stream`` may have fewer bytes remaining than ``chunk_size``
|
||||
so it may not always be the case that
|
||||
``end_byte == start_byte + chunk_size - 1``.
|
||||
|
||||
Args:
|
||||
stream (IO[bytes]): The stream (i.e. file-like object).
|
||||
chunk_size (int): The size of the chunk to be read from the ``stream``.
|
||||
total_bytes (Optional[int]): The (expected) total number of bytes
|
||||
in the ``stream``.
|
||||
|
||||
Returns:
|
||||
Tuple[int, bytes, str]: Triple of:
|
||||
|
||||
* the start byte index
|
||||
* the content in between the start and end bytes (inclusive)
|
||||
* content range header for the chunk (slice) that has been read
|
||||
|
||||
Raises:
|
||||
ValueError: If ``total_bytes == 0`` but ``stream.read()`` yields
|
||||
non-empty content.
|
||||
ValueError: If there is no data left to consume. This corresponds
|
||||
exactly to the case ``end_byte < start_byte``, which can only
|
||||
occur if ``end_byte == start_byte - 1``.
|
||||
"""
|
||||
start_byte = stream.tell()
|
||||
if total_bytes is not None and start_byte + chunk_size >= total_bytes > 0:
|
||||
payload = stream.read(total_bytes - start_byte)
|
||||
else:
|
||||
payload = stream.read(chunk_size)
|
||||
end_byte = stream.tell() - 1
|
||||
|
||||
num_bytes_read = len(payload)
|
||||
if total_bytes is None:
|
||||
if num_bytes_read < chunk_size:
|
||||
# We now **KNOW** the total number of bytes.
|
||||
total_bytes = end_byte + 1
|
||||
elif total_bytes == 0:
|
||||
# NOTE: We also expect ``start_byte == 0`` here but don't check
|
||||
# because ``_prepare_initiate_request()`` requires the
|
||||
# stream to be at the beginning.
|
||||
if num_bytes_read != 0:
|
||||
raise ValueError(
|
||||
"Stream specified as empty, but produced non-empty content."
|
||||
)
|
||||
else:
|
||||
if num_bytes_read == 0:
|
||||
raise ValueError(
|
||||
"Stream is already exhausted. There is no content remaining."
|
||||
)
|
||||
|
||||
content_range = get_content_range(start_byte, end_byte, total_bytes)
|
||||
return start_byte, payload, content_range
|
||||
|
||||
|
||||
def get_content_range(start_byte, end_byte, total_bytes):
|
||||
"""Convert start, end and total into content range header.
|
||||
|
||||
If ``total_bytes`` is not known, uses "bytes {start}-{end}/*".
|
||||
If we are dealing with an empty range (i.e. ``end_byte < start_byte``)
|
||||
then "bytes */{total}" is used.
|
||||
|
||||
This function **ASSUMES** that if the size is not known, the caller will
|
||||
not also pass an empty range.
|
||||
|
||||
Args:
|
||||
start_byte (int): The start (inclusive) of the byte range.
|
||||
end_byte (int): The end (inclusive) of the byte range.
|
||||
total_bytes (Optional[int]): The number of bytes in the byte
|
||||
range (if known).
|
||||
|
||||
Returns:
|
||||
str: The content range header.
|
||||
"""
|
||||
if total_bytes is None:
|
||||
return _RANGE_UNKNOWN_TEMPLATE.format(start_byte, end_byte)
|
||||
elif end_byte < start_byte:
|
||||
return _EMPTY_RANGE_TEMPLATE.format(total_bytes)
|
||||
else:
|
||||
return _CONTENT_RANGE_TEMPLATE.format(start_byte, end_byte, total_bytes)
|
||||
@@ -0,0 +1,682 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""``requests`` utilities for Google Media Downloads and Resumable Uploads.
|
||||
|
||||
This sub-package assumes callers will use the `requests`_ library
|
||||
as transport and `google-auth`_ for sending authenticated HTTP traffic
|
||||
with ``requests``.
|
||||
|
||||
.. _requests: http://docs.python-requests.org/
|
||||
.. _google-auth: https://google-auth.readthedocs.io/
|
||||
|
||||
====================
|
||||
Authorized Transport
|
||||
====================
|
||||
|
||||
To use ``google-auth`` and ``requests`` to create an authorized transport
|
||||
that has read-only access to Google Cloud Storage (GCS):
|
||||
|
||||
.. testsetup:: get-credentials
|
||||
|
||||
import google.auth
|
||||
import google.auth.credentials as creds_mod
|
||||
import mock
|
||||
|
||||
def mock_default(scopes=None):
|
||||
credentials = mock.Mock(spec=creds_mod.Credentials)
|
||||
return credentials, 'mock-project'
|
||||
|
||||
# Patch the ``default`` function on the module.
|
||||
original_default = google.auth.default
|
||||
google.auth.default = mock_default
|
||||
|
||||
.. doctest:: get-credentials
|
||||
|
||||
>>> import google.auth
|
||||
>>> import google.auth.transport.requests as tr_requests
|
||||
>>>
|
||||
>>> ro_scope = 'https://www.googleapis.com/auth/devstorage.read_only'
|
||||
>>> credentials, _ = google.auth.default(scopes=(ro_scope,))
|
||||
>>> transport = tr_requests.AuthorizedSession(credentials)
|
||||
>>> transport
|
||||
<google.auth.transport.requests.AuthorizedSession object at 0x...>
|
||||
|
||||
.. testcleanup:: get-credentials
|
||||
|
||||
# Put back the correct ``default`` function on the module.
|
||||
google.auth.default = original_default
|
||||
|
||||
================
|
||||
Simple Downloads
|
||||
================
|
||||
|
||||
To download an object from Google Cloud Storage, construct the media URL
|
||||
for the GCS object and download it with an authorized transport that has
|
||||
access to the resource:
|
||||
|
||||
.. testsetup:: basic-download
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
bucket = 'bucket-foo'
|
||||
blob_name = 'file.txt'
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
fake_response.headers['Content-Length'] = '1364156'
|
||||
fake_content = mock.MagicMock(spec=['__len__'])
|
||||
fake_content.__len__.return_value = 1364156
|
||||
fake_response._content = fake_content
|
||||
|
||||
get_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=get_method, spec=['request'])
|
||||
|
||||
.. doctest:: basic-download
|
||||
|
||||
>>> from google.resumable_media.requests import Download
|
||||
>>>
|
||||
>>> url_template = (
|
||||
... 'https://www.googleapis.com/download/storage/v1/b/'
|
||||
... '{bucket}/o/{blob_name}?alt=media')
|
||||
>>> media_url = url_template.format(
|
||||
... bucket=bucket, blob_name=blob_name)
|
||||
>>>
|
||||
>>> download = Download(media_url)
|
||||
>>> response = download.consume(transport)
|
||||
>>> download.finished
|
||||
True
|
||||
>>> response
|
||||
<Response [200]>
|
||||
>>> response.headers['Content-Length']
|
||||
'1364156'
|
||||
>>> len(response.content)
|
||||
1364156
|
||||
|
||||
To download only a portion of the bytes in the object,
|
||||
specify ``start`` and ``end`` byte positions (both optional):
|
||||
|
||||
.. testsetup:: basic-download-with-slice
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google.resumable_media.requests import Download
|
||||
|
||||
media_url = 'http://test.invalid'
|
||||
start = 4096
|
||||
end = 8191
|
||||
slice_size = end - start + 1
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.PARTIAL_CONTENT)
|
||||
fake_response.headers['Content-Length'] = '{:d}'.format(slice_size)
|
||||
content_range = 'bytes {:d}-{:d}/1364156'.format(start, end)
|
||||
fake_response.headers['Content-Range'] = content_range
|
||||
fake_content = mock.MagicMock(spec=['__len__'])
|
||||
fake_content.__len__.return_value = slice_size
|
||||
fake_response._content = fake_content
|
||||
|
||||
get_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=get_method, spec=['request'])
|
||||
|
||||
.. doctest:: basic-download-with-slice
|
||||
|
||||
>>> download = Download(media_url, start=4096, end=8191)
|
||||
>>> response = download.consume(transport)
|
||||
>>> download.finished
|
||||
True
|
||||
>>> response
|
||||
<Response [206]>
|
||||
>>> response.headers['Content-Length']
|
||||
'4096'
|
||||
>>> response.headers['Content-Range']
|
||||
'bytes 4096-8191/1364156'
|
||||
>>> len(response.content)
|
||||
4096
|
||||
|
||||
=================
|
||||
Chunked Downloads
|
||||
=================
|
||||
|
||||
For very large objects or objects of unknown size, it may make more sense
|
||||
to download the object in chunks rather than all at once. This can be done
|
||||
to avoid dropped connections with a poor internet connection or can allow
|
||||
multiple chunks to be downloaded in parallel to speed up the total
|
||||
download.
|
||||
|
||||
A :class:`.ChunkedDownload` uses the same media URL and authorized
|
||||
transport that a basic :class:`.Download` would use, but also
|
||||
requires a chunk size and a write-able byte ``stream``. The chunk size is used
|
||||
to determine how much of the resouce to consume with each request and the
|
||||
stream is to allow the resource to be written out (e.g. to disk) without
|
||||
having to fit in memory all at once.
|
||||
|
||||
.. testsetup:: chunked-download
|
||||
|
||||
import io
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
media_url = 'http://test.invalid'
|
||||
|
||||
fifty_mb = 50 * 1024 * 1024
|
||||
one_gb = 1024 * 1024 * 1024
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.PARTIAL_CONTENT)
|
||||
fake_response.headers['Content-Length'] = '{:d}'.format(fifty_mb)
|
||||
content_range = 'bytes 0-{:d}/{:d}'.format(fifty_mb - 1, one_gb)
|
||||
fake_response.headers['Content-Range'] = content_range
|
||||
fake_content_begin = b'The beginning of the chunk...'
|
||||
fake_content = fake_content_begin + b'1' * (fifty_mb - 29)
|
||||
fake_response._content = fake_content
|
||||
|
||||
get_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=get_method, spec=['request'])
|
||||
|
||||
.. doctest:: chunked-download
|
||||
|
||||
>>> from google.resumable_media.requests import ChunkedDownload
|
||||
>>>
|
||||
>>> chunk_size = 50 * 1024 * 1024 # 50MB
|
||||
>>> stream = io.BytesIO()
|
||||
>>> download = ChunkedDownload(
|
||||
... media_url, chunk_size, stream)
|
||||
>>> # Check the state of the download before starting.
|
||||
>>> download.bytes_downloaded
|
||||
0
|
||||
>>> download.total_bytes is None
|
||||
True
|
||||
>>> response = download.consume_next_chunk(transport)
|
||||
>>> # Check the state of the download after consuming one chunk.
|
||||
>>> download.finished
|
||||
False
|
||||
>>> download.bytes_downloaded # chunk_size
|
||||
52428800
|
||||
>>> download.total_bytes # 1GB
|
||||
1073741824
|
||||
>>> response
|
||||
<Response [206]>
|
||||
>>> response.headers['Content-Length']
|
||||
'52428800'
|
||||
>>> response.headers['Content-Range']
|
||||
'bytes 0-52428799/1073741824'
|
||||
>>> len(response.content) == chunk_size
|
||||
True
|
||||
>>> stream.seek(0)
|
||||
0
|
||||
>>> stream.read(29)
|
||||
b'The beginning of the chunk...'
|
||||
|
||||
The download will change it's ``finished`` status to :data:`True`
|
||||
once the final chunk is consumed. In some cases, the final chunk may
|
||||
not be the same size as the other chunks:
|
||||
|
||||
.. testsetup:: chunked-download-end
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google.resumable_media.requests import ChunkedDownload
|
||||
|
||||
media_url = 'http://test.invalid'
|
||||
|
||||
fifty_mb = 50 * 1024 * 1024
|
||||
one_gb = 1024 * 1024 * 1024
|
||||
stream = mock.Mock(spec=['write'])
|
||||
download = ChunkedDownload(media_url, fifty_mb, stream)
|
||||
download._bytes_downloaded = 20 * fifty_mb
|
||||
download._total_bytes = one_gb
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.PARTIAL_CONTENT)
|
||||
slice_size = one_gb - 20 * fifty_mb
|
||||
fake_response.headers['Content-Length'] = '{:d}'.format(slice_size)
|
||||
content_range = 'bytes {:d}-{:d}/{:d}'.format(
|
||||
20 * fifty_mb, one_gb - 1, one_gb)
|
||||
fake_response.headers['Content-Range'] = content_range
|
||||
fake_content = mock.MagicMock(spec=['__len__'])
|
||||
fake_content.__len__.return_value = slice_size
|
||||
fake_response._content = fake_content
|
||||
|
||||
get_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=get_method, spec=['request'])
|
||||
|
||||
.. doctest:: chunked-download-end
|
||||
|
||||
>>> # The state of the download in progress.
|
||||
>>> download.finished
|
||||
False
|
||||
>>> download.bytes_downloaded # 20 chunks at 50MB
|
||||
1048576000
|
||||
>>> download.total_bytes # 1GB
|
||||
1073741824
|
||||
>>> response = download.consume_next_chunk(transport)
|
||||
>>> # The state of the download after consuming the final chunk.
|
||||
>>> download.finished
|
||||
True
|
||||
>>> download.bytes_downloaded == download.total_bytes
|
||||
True
|
||||
>>> response
|
||||
<Response [206]>
|
||||
>>> response.headers['Content-Length']
|
||||
'25165824'
|
||||
>>> response.headers['Content-Range']
|
||||
'bytes 1048576000-1073741823/1073741824'
|
||||
>>> len(response.content) < download.chunk_size
|
||||
True
|
||||
|
||||
In addition, a :class:`.ChunkedDownload` can also take optional
|
||||
``start`` and ``end`` byte positions.
|
||||
|
||||
Usually, no checksum is returned with a chunked download. Even if one is returned,
|
||||
it is not validated. If you need to validate the checksum, you can do so
|
||||
by buffering the chunks and validating the checksum against the completed download.
|
||||
|
||||
==============
|
||||
Simple Uploads
|
||||
==============
|
||||
|
||||
Among the three supported upload classes, the simplest is
|
||||
:class:`.SimpleUpload`. A simple upload should be used when the resource
|
||||
being uploaded is small and when there is no metadata (other than the name)
|
||||
associated with the resource.
|
||||
|
||||
.. testsetup:: simple-upload
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
bucket = 'some-bucket'
|
||||
blob_name = 'file.txt'
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
payload = {
|
||||
'bucket': bucket,
|
||||
'contentType': 'text/plain',
|
||||
'md5Hash': 'M0XLEsX9/sMdiI+4pB4CAQ==',
|
||||
'name': blob_name,
|
||||
'size': '27',
|
||||
}
|
||||
fake_response._content = json.dumps(payload).encode('utf-8')
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
.. doctest:: simple-upload
|
||||
:options: +NORMALIZE_WHITESPACE
|
||||
|
||||
>>> from google.resumable_media.requests import SimpleUpload
|
||||
>>>
|
||||
>>> url_template = (
|
||||
... 'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?'
|
||||
... 'uploadType=media&'
|
||||
... 'name={blob_name}')
|
||||
>>> upload_url = url_template.format(
|
||||
... bucket=bucket, blob_name=blob_name)
|
||||
>>>
|
||||
>>> upload = SimpleUpload(upload_url)
|
||||
>>> data = b'Some not too large content.'
|
||||
>>> content_type = 'text/plain'
|
||||
>>> response = upload.transmit(transport, data, content_type)
|
||||
>>> upload.finished
|
||||
True
|
||||
>>> response
|
||||
<Response [200]>
|
||||
>>> json_response = response.json()
|
||||
>>> json_response['bucket'] == bucket
|
||||
True
|
||||
>>> json_response['name'] == blob_name
|
||||
True
|
||||
>>> json_response['contentType'] == content_type
|
||||
True
|
||||
>>> json_response['md5Hash']
|
||||
'M0XLEsX9/sMdiI+4pB4CAQ=='
|
||||
>>> int(json_response['size']) == len(data)
|
||||
True
|
||||
|
||||
In the rare case that an upload fails, an :exc:`.InvalidResponse`
|
||||
will be raised:
|
||||
|
||||
.. testsetup:: simple-upload-fail
|
||||
|
||||
import time
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google import resumable_media
|
||||
from google.resumable_media import _helpers
|
||||
from google.resumable_media.requests import SimpleUpload as constructor
|
||||
|
||||
upload_url = 'http://test.invalid'
|
||||
data = b'Some not too large content.'
|
||||
content_type = 'text/plain'
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.SERVICE_UNAVAILABLE)
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
time_sleep = time.sleep
|
||||
def dont_sleep(seconds):
|
||||
raise RuntimeError('No sleep', seconds)
|
||||
|
||||
def SimpleUpload(*args, **kwargs):
|
||||
upload = constructor(*args, **kwargs)
|
||||
# Mock the cumulative sleep to avoid retries (and `time.sleep()`).
|
||||
upload._retry_strategy = resumable_media.RetryStrategy(
|
||||
max_cumulative_retry=-1.0)
|
||||
return upload
|
||||
|
||||
time.sleep = dont_sleep
|
||||
|
||||
.. doctest:: simple-upload-fail
|
||||
:options: +NORMALIZE_WHITESPACE
|
||||
|
||||
>>> upload = SimpleUpload(upload_url)
|
||||
>>> error = None
|
||||
>>> try:
|
||||
... upload.transmit(transport, data, content_type)
|
||||
... except resumable_media.InvalidResponse as caught_exc:
|
||||
... error = caught_exc
|
||||
...
|
||||
>>> error
|
||||
InvalidResponse('Request failed with status code', 503,
|
||||
'Expected one of', <HTTPStatus.OK: 200>)
|
||||
>>> error.response
|
||||
<Response [503]>
|
||||
>>>
|
||||
>>> upload.finished
|
||||
True
|
||||
|
||||
.. testcleanup:: simple-upload-fail
|
||||
|
||||
# Put back the correct ``sleep`` function on the ``time`` module.
|
||||
time.sleep = time_sleep
|
||||
|
||||
Even in the case of failure, we see that the upload is
|
||||
:attr:`~.SimpleUpload.finished`, i.e. it cannot be re-used.
|
||||
|
||||
=================
|
||||
Multipart Uploads
|
||||
=================
|
||||
|
||||
After the simple upload, the :class:`.MultipartUpload` can be used to
|
||||
achieve essentially the same task. However, a multipart upload allows some
|
||||
metadata about the resource to be sent along as well. (This is the "multi":
|
||||
we send a first part with the metadata and a second part with the actual
|
||||
bytes in the resource.)
|
||||
|
||||
Usage is similar to the simple upload, but :meth:`~.MultipartUpload.transmit`
|
||||
accepts an extra required argument: ``metadata``.
|
||||
|
||||
.. testsetup:: multipart-upload
|
||||
|
||||
import json
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
bucket = 'some-bucket'
|
||||
blob_name = 'file.txt'
|
||||
data = b'Some not too large content.'
|
||||
content_type = 'text/plain'
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
payload = {
|
||||
'bucket': bucket,
|
||||
'name': blob_name,
|
||||
'metadata': {'color': 'grurple'},
|
||||
}
|
||||
fake_response._content = json.dumps(payload).encode('utf-8')
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
.. doctest:: multipart-upload
|
||||
|
||||
>>> from google.resumable_media.requests import MultipartUpload
|
||||
>>>
|
||||
>>> url_template = (
|
||||
... 'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?'
|
||||
... 'uploadType=multipart')
|
||||
>>> upload_url = url_template.format(bucket=bucket)
|
||||
>>>
|
||||
>>> upload = MultipartUpload(upload_url)
|
||||
>>> metadata = {
|
||||
... 'name': blob_name,
|
||||
... 'metadata': {
|
||||
... 'color': 'grurple',
|
||||
... },
|
||||
... }
|
||||
>>> response = upload.transmit(transport, data, metadata, content_type)
|
||||
>>> upload.finished
|
||||
True
|
||||
>>> response
|
||||
<Response [200]>
|
||||
>>> json_response = response.json()
|
||||
>>> json_response['bucket'] == bucket
|
||||
True
|
||||
>>> json_response['name'] == blob_name
|
||||
True
|
||||
>>> json_response['metadata'] == metadata['metadata']
|
||||
True
|
||||
|
||||
As with the simple upload, in the case of failure an :exc:`.InvalidResponse`
|
||||
is raised, enclosing the :attr:`~.InvalidResponse.response` that caused
|
||||
the failure and the ``upload`` object cannot be re-used after a failure.
|
||||
|
||||
=================
|
||||
Resumable Uploads
|
||||
=================
|
||||
|
||||
A :class:`.ResumableUpload` deviates from the other two upload classes:
|
||||
it transmits a resource over the course of multiple requests. This
|
||||
is intended to be used in cases where:
|
||||
|
||||
* the size of the resource is not known (i.e. it is generated on the fly)
|
||||
* requests must be short-lived
|
||||
* the client has request **size** limitations
|
||||
* the resource is too large to fit into memory
|
||||
|
||||
In general, a resource should be sent in a **single** request to avoid
|
||||
latency and reduce QPS. See `GCS best practices`_ for more things to
|
||||
consider when using a resumable upload.
|
||||
|
||||
.. _GCS best practices: https://cloud.google.com/storage/docs/\
|
||||
best-practices#uploading
|
||||
|
||||
After creating a :class:`.ResumableUpload` instance, a
|
||||
**resumable upload session** must be initiated to let the server know that
|
||||
a series of chunked upload requests will be coming and to obtain an
|
||||
``upload_id`` for the session. In contrast to the other two upload classes,
|
||||
:meth:`~.ResumableUpload.initiate` takes a byte ``stream`` as input rather
|
||||
than raw bytes as ``data``. This can be a file object, a :class:`~io.BytesIO`
|
||||
object or any other stream implementing the same interface.
|
||||
|
||||
.. testsetup:: resumable-initiate
|
||||
|
||||
import io
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
bucket = 'some-bucket'
|
||||
blob_name = 'file.txt'
|
||||
data = b'Some resumable bytes.'
|
||||
content_type = 'text/plain'
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
fake_response._content = b''
|
||||
upload_id = 'ABCdef189XY_super_serious'
|
||||
resumable_url_template = (
|
||||
'https://www.googleapis.com/upload/storage/v1/b/{bucket}'
|
||||
'/o?uploadType=resumable&upload_id={upload_id}')
|
||||
resumable_url = resumable_url_template.format(
|
||||
bucket=bucket, upload_id=upload_id)
|
||||
fake_response.headers['location'] = resumable_url
|
||||
fake_response.headers['x-guploader-uploadid'] = upload_id
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
.. doctest:: resumable-initiate
|
||||
|
||||
>>> from google.resumable_media.requests import ResumableUpload
|
||||
>>>
|
||||
>>> url_template = (
|
||||
... 'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?'
|
||||
... 'uploadType=resumable')
|
||||
>>> upload_url = url_template.format(bucket=bucket)
|
||||
>>>
|
||||
>>> chunk_size = 1024 * 1024 # 1MB
|
||||
>>> upload = ResumableUpload(upload_url, chunk_size)
|
||||
>>> stream = io.BytesIO(data)
|
||||
>>> # The upload doesn't know how "big" it is until seeing a stream.
|
||||
>>> upload.total_bytes is None
|
||||
True
|
||||
>>> metadata = {'name': blob_name}
|
||||
>>> response = upload.initiate(transport, stream, metadata, content_type)
|
||||
>>> response
|
||||
<Response [200]>
|
||||
>>> upload.resumable_url == response.headers['Location']
|
||||
True
|
||||
>>> upload.total_bytes == len(data)
|
||||
True
|
||||
>>> upload_id = response.headers['X-GUploader-UploadID']
|
||||
>>> upload_id
|
||||
'ABCdef189XY_super_serious'
|
||||
>>> upload.resumable_url == upload_url + '&upload_id=' + upload_id
|
||||
True
|
||||
|
||||
Once a :class:`.ResumableUpload` has been initiated, the resource is
|
||||
transmitted in chunks until completion:
|
||||
|
||||
.. testsetup:: resumable-transmit
|
||||
|
||||
import io
|
||||
import json
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google import resumable_media
|
||||
import google.resumable_media.requests.upload as upload_mod
|
||||
|
||||
data = b'01234567891'
|
||||
stream = io.BytesIO(data)
|
||||
# Create an "already initiated" upload.
|
||||
upload_url = 'http://test.invalid'
|
||||
chunk_size = 256 * 1024 # 256KB
|
||||
upload = upload_mod.ResumableUpload(upload_url, chunk_size)
|
||||
upload._resumable_url = 'http://test.invalid?upload_id=mocked'
|
||||
upload._stream = stream
|
||||
upload._content_type = 'text/plain'
|
||||
upload._total_bytes = len(data)
|
||||
|
||||
# After-the-fact update the chunk size so that len(data)
|
||||
# is split into three.
|
||||
upload._chunk_size = 4
|
||||
# Make three fake responses.
|
||||
fake_response0 = requests.Response()
|
||||
fake_response0.status_code = http.client.PERMANENT_REDIRECT
|
||||
fake_response0.headers['range'] = 'bytes=0-3'
|
||||
|
||||
fake_response1 = requests.Response()
|
||||
fake_response1.status_code = http.client.PERMANENT_REDIRECT
|
||||
fake_response1.headers['range'] = 'bytes=0-7'
|
||||
|
||||
fake_response2 = requests.Response()
|
||||
fake_response2.status_code = int(http.client.OK)
|
||||
bucket = 'some-bucket'
|
||||
blob_name = 'file.txt'
|
||||
payload = {
|
||||
'bucket': bucket,
|
||||
'name': blob_name,
|
||||
'size': '{:d}'.format(len(data)),
|
||||
}
|
||||
fake_response2._content = json.dumps(payload).encode('utf-8')
|
||||
|
||||
# Use the fake responses to mock a transport.
|
||||
responses = [fake_response0, fake_response1, fake_response2]
|
||||
put_method = mock.Mock(side_effect=responses, spec=[])
|
||||
transport = mock.Mock(request=put_method, spec=['request'])
|
||||
|
||||
.. doctest:: resumable-transmit
|
||||
|
||||
>>> response0 = upload.transmit_next_chunk(transport)
|
||||
>>> response0
|
||||
<Response [308]>
|
||||
>>> upload.finished
|
||||
False
|
||||
>>> upload.bytes_uploaded == upload.chunk_size
|
||||
True
|
||||
>>>
|
||||
>>> response1 = upload.transmit_next_chunk(transport)
|
||||
>>> response1
|
||||
<Response [308]>
|
||||
>>> upload.finished
|
||||
False
|
||||
>>> upload.bytes_uploaded == 2 * upload.chunk_size
|
||||
True
|
||||
>>>
|
||||
>>> response2 = upload.transmit_next_chunk(transport)
|
||||
>>> response2
|
||||
<Response [200]>
|
||||
>>> upload.finished
|
||||
True
|
||||
>>> upload.bytes_uploaded == upload.total_bytes
|
||||
True
|
||||
>>> json_response = response2.json()
|
||||
>>> json_response['bucket'] == bucket
|
||||
True
|
||||
>>> json_response['name'] == blob_name
|
||||
True
|
||||
"""
|
||||
from google._async_resumable_media.requests.download import ChunkedDownload
|
||||
from google._async_resumable_media.requests.download import Download
|
||||
from google._async_resumable_media.requests.upload import MultipartUpload
|
||||
from google._async_resumable_media.requests.download import RawChunkedDownload
|
||||
from google._async_resumable_media.requests.download import RawDownload
|
||||
from google._async_resumable_media.requests.upload import ResumableUpload
|
||||
from google._async_resumable_media.requests.upload import SimpleUpload
|
||||
|
||||
|
||||
__all__ = [
|
||||
"ChunkedDownload",
|
||||
"Download",
|
||||
"MultipartUpload",
|
||||
"RawChunkedDownload",
|
||||
"RawDownload",
|
||||
"ResumableUpload",
|
||||
"SimpleUpload",
|
||||
]
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,155 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Shared utilities used by both downloads and uploads.
|
||||
|
||||
This utilities are explicitly catered to ``requests``-like transports.
|
||||
"""
|
||||
|
||||
|
||||
import functools
|
||||
|
||||
from google._async_resumable_media import _helpers
|
||||
from google.resumable_media import common
|
||||
|
||||
from google.auth.transport import _aiohttp_requests as aiohttp_requests # type: ignore
|
||||
import aiohttp # type: ignore
|
||||
|
||||
_DEFAULT_RETRY_STRATEGY = common.RetryStrategy()
|
||||
_SINGLE_GET_CHUNK_SIZE = 8192
|
||||
|
||||
|
||||
# The number of seconds to wait to establish a connection
|
||||
# (connect() call on socket). Avoid setting this to a multiple of 3 to not
|
||||
# Align with TCP Retransmission timing. (typically 2.5-3s)
|
||||
_DEFAULT_CONNECT_TIMEOUT = 61
|
||||
# The number of seconds to wait between bytes sent from the server.
|
||||
_DEFAULT_READ_TIMEOUT = 60
|
||||
_DEFAULT_TIMEOUT = aiohttp.ClientTimeout(
|
||||
connect=_DEFAULT_CONNECT_TIMEOUT, sock_read=_DEFAULT_READ_TIMEOUT
|
||||
)
|
||||
|
||||
|
||||
class RequestsMixin(object):
|
||||
"""Mix-in class implementing ``requests``-specific behavior.
|
||||
|
||||
These are methods that are more general purpose, with implementations
|
||||
specific to the types defined in ``requests``.
|
||||
"""
|
||||
|
||||
@staticmethod
|
||||
def _get_status_code(response):
|
||||
"""Access the status code from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Returns:
|
||||
int: The status code.
|
||||
"""
|
||||
return response.status
|
||||
|
||||
@staticmethod
|
||||
def _get_headers(response):
|
||||
"""Access the headers from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Returns:
|
||||
~requests.structures.CaseInsensitiveDict: The header mapping (keys
|
||||
are case-insensitive).
|
||||
"""
|
||||
# For Async testing,`_headers` is modified instead of headers
|
||||
# access via the internal field.
|
||||
return response._headers
|
||||
|
||||
@staticmethod
|
||||
async def _get_body(response):
|
||||
"""Access the response body from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Returns:
|
||||
bytes: The body of the ``response``.
|
||||
"""
|
||||
wrapped_response = aiohttp_requests._CombinedResponse(response)
|
||||
content = await wrapped_response.data.read()
|
||||
return content
|
||||
|
||||
|
||||
class RawRequestsMixin(RequestsMixin):
|
||||
@staticmethod
|
||||
async def _get_body(response):
|
||||
"""Access the response body from an HTTP response.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Returns:
|
||||
bytes: The body of the ``response``.
|
||||
"""
|
||||
|
||||
wrapped_response = aiohttp_requests._CombinedResponse(response)
|
||||
content = await wrapped_response.raw_content()
|
||||
return content
|
||||
|
||||
|
||||
async def http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=None,
|
||||
headers=None,
|
||||
retry_strategy=_DEFAULT_RETRY_STRATEGY,
|
||||
**transport_kwargs
|
||||
):
|
||||
"""Make an HTTP request.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can make
|
||||
authenticated requests via a ``request()`` method. This method
|
||||
must accept an HTTP method, an upload URL, a ``data`` keyword
|
||||
argument and a ``headers`` keyword argument.
|
||||
method (str): The HTTP method for the request.
|
||||
url (str): The URL for the request.
|
||||
data (Optional[bytes]): The body of the request.
|
||||
headers (Mapping[str, str]): The headers for the request (``transport``
|
||||
may also add additional headers).
|
||||
retry_strategy (~google.resumable_media.common.RetryStrategy): The
|
||||
strategy to use if the request fails and must be retried.
|
||||
transport_kwargs (Dict[str, str]): Extra keyword arguments to be
|
||||
passed along to ``transport.request``.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The return value of ``transport.request()``.
|
||||
"""
|
||||
|
||||
# NOTE(asyncio/aiohttp): Sync versions use a tuple for two timeouts,
|
||||
# default connect timeout and read timeout. Since async requests only
|
||||
# accepts a single value, this is using the connect timeout. This logic
|
||||
# diverges from the sync implementation.
|
||||
if "timeout" not in transport_kwargs:
|
||||
timeout = _DEFAULT_TIMEOUT
|
||||
transport_kwargs["timeout"] = timeout
|
||||
|
||||
func = functools.partial(
|
||||
transport.request, method, url, data=data, headers=headers, **transport_kwargs
|
||||
)
|
||||
|
||||
resp = await _helpers.wait_and_retry(
|
||||
func, RequestsMixin._get_status_code, retry_strategy
|
||||
)
|
||||
return resp
|
||||
@@ -0,0 +1,465 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Support for downloading media from Google APIs."""
|
||||
|
||||
import urllib3.response # type: ignore
|
||||
import http
|
||||
|
||||
from google._async_resumable_media import _download
|
||||
from google._async_resumable_media import _helpers
|
||||
from google._async_resumable_media.requests import _request_helpers
|
||||
from google.resumable_media import common
|
||||
from google.resumable_media import _helpers as sync_helpers
|
||||
from google.resumable_media.requests import download
|
||||
|
||||
_CHECKSUM_MISMATCH = download._CHECKSUM_MISMATCH
|
||||
|
||||
|
||||
class Download(_request_helpers.RequestsMixin, _download.Download):
|
||||
"""Helper to manage downloading a resource from a Google API.
|
||||
|
||||
"Slices" of the resource can be retrieved by specifying a range
|
||||
with ``start`` and / or ``end``. However, in typical usage, neither
|
||||
``start`` nor ``end`` is expected to be provided.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
the downloaded resource can be written to.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, but ``end`` is provided, will download from the
|
||||
beginning to ``end`` of the media.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, but ``start`` is provided, will download from the
|
||||
``start`` to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. The response headers must contain
|
||||
a checksum of the requested type. If the headers lack an
|
||||
appropriate checksum (for instance in the case of transcoded or
|
||||
ranged downloads where the remote service does not know the
|
||||
correct checksum) an INFO-level log will be emitted. Supported
|
||||
values are "md5", "crc32c" and None. The default is "md5".
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
"""
|
||||
|
||||
async def _write_to_stream(self, response):
|
||||
"""Write response body to a write-able stream.
|
||||
|
||||
.. note:
|
||||
|
||||
This method assumes that the ``_stream`` attribute is set on the
|
||||
current download.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.DataCorruption: If the download's
|
||||
checksum doesn't agree with server-computed checksum.
|
||||
"""
|
||||
|
||||
# `_get_expected_checksum()` may return None even if a checksum was
|
||||
# requested, in which case it will emit an info log _MISSING_CHECKSUM.
|
||||
# If an invalid checksum type is specified, this will raise ValueError.
|
||||
expected_checksum, checksum_object = sync_helpers._get_expected_checksum(
|
||||
response, self._get_headers, self.media_url, checksum_type=self.checksum
|
||||
)
|
||||
|
||||
local_checksum_object = _add_decoder(response, checksum_object)
|
||||
|
||||
async for chunk in response.content.iter_chunked(
|
||||
_request_helpers._SINGLE_GET_CHUNK_SIZE
|
||||
):
|
||||
self._stream.write(chunk)
|
||||
local_checksum_object.update(chunk)
|
||||
|
||||
# Don't validate the checksum for partial responses.
|
||||
if (
|
||||
expected_checksum is not None
|
||||
and response.status != http.client.PARTIAL_CONTENT
|
||||
):
|
||||
actual_checksum = sync_helpers.prepare_checksum_digest(
|
||||
checksum_object.digest()
|
||||
)
|
||||
if actual_checksum != expected_checksum:
|
||||
msg = _CHECKSUM_MISMATCH.format(
|
||||
self.media_url,
|
||||
expected_checksum,
|
||||
actual_checksum,
|
||||
checksum_type=self.checksum.upper(),
|
||||
)
|
||||
raise common.DataCorruption(response, msg)
|
||||
|
||||
async def consume(self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT):
|
||||
"""Consume the resource to be downloaded.
|
||||
|
||||
If a ``stream`` is attached to this download, then the downloaded
|
||||
resource will be written to the stream.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.DataCorruption: If the download's
|
||||
checksum doesn't agree with server-computed checksum.
|
||||
ValueError: If the current :class:`Download` has already
|
||||
finished.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request()
|
||||
# NOTE: We assume "payload is None" but pass it along anyway.
|
||||
request_kwargs = {
|
||||
"data": payload,
|
||||
"headers": headers,
|
||||
"retry_strategy": self._retry_strategy,
|
||||
"timeout": timeout,
|
||||
}
|
||||
|
||||
if self._stream is not None:
|
||||
request_kwargs["stream"] = True
|
||||
|
||||
result = await _request_helpers.http_request(
|
||||
transport, method, url, **request_kwargs
|
||||
)
|
||||
|
||||
self._process_response(result)
|
||||
|
||||
if self._stream is not None:
|
||||
await self._write_to_stream(result)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class RawDownload(_request_helpers.RawRequestsMixin, _download.Download):
|
||||
"""Helper to manage downloading a raw resource from a Google API.
|
||||
|
||||
"Slices" of the resource can be retrieved by specifying a range
|
||||
with ``start`` and / or ``end``. However, in typical usage, neither
|
||||
``start`` nor ``end`` is expected to be provided.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
the downloaded resource can be written to.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, but ``end`` is provided, will download from the
|
||||
beginning to ``end`` of the media.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, but ``start`` is provided, will download from the
|
||||
``start`` to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. The response headers must contain
|
||||
a checksum of the requested type. If the headers lack an
|
||||
appropriate checksum (for instance in the case of transcoded or
|
||||
ranged downloads where the remote service does not know the
|
||||
correct checksum) an INFO-level log will be emitted. Supported
|
||||
values are "md5", "crc32c" and None. The default is "md5".
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
"""
|
||||
|
||||
async def _write_to_stream(self, response):
|
||||
"""Write response body to a write-able stream.
|
||||
|
||||
.. note:
|
||||
|
||||
This method assumes that the ``_stream`` attribute is set on the
|
||||
current download.
|
||||
|
||||
Args:
|
||||
response (~requests.Response): The HTTP response object.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.DataCorruption: If the download's
|
||||
checksum doesn't agree with server-computed checksum.
|
||||
"""
|
||||
|
||||
# `_get_expected_checksum()` may return None even if a checksum was
|
||||
# requested, in which case it will emit an info log _MISSING_CHECKSUM.
|
||||
# If an invalid checksum type is specified, this will raise ValueError.
|
||||
expected_checksum, checksum_object = sync_helpers._get_expected_checksum(
|
||||
response, self._get_headers, self.media_url, checksum_type=self.checksum
|
||||
)
|
||||
|
||||
async for chunk in response.content.iter_chunked(
|
||||
_request_helpers._SINGLE_GET_CHUNK_SIZE
|
||||
):
|
||||
self._stream.write(chunk)
|
||||
checksum_object.update(chunk)
|
||||
|
||||
# Don't validate the checksum for partial responses.
|
||||
if (
|
||||
expected_checksum is not None
|
||||
and response.status != http.client.PARTIAL_CONTENT
|
||||
):
|
||||
actual_checksum = sync_helpers.prepare_checksum_digest(
|
||||
checksum_object.digest()
|
||||
)
|
||||
|
||||
if actual_checksum != expected_checksum:
|
||||
msg = _CHECKSUM_MISMATCH.format(
|
||||
self.media_url,
|
||||
expected_checksum,
|
||||
actual_checksum,
|
||||
checksum_type=self.checksum.upper(),
|
||||
)
|
||||
raise common.DataCorruption(response, msg)
|
||||
|
||||
async def consume(self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT):
|
||||
"""Consume the resource to be downloaded.
|
||||
|
||||
If a ``stream`` is attached to this download, then the downloaded
|
||||
resource will be written to the stream.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
timeout (Optional[Union[float, Tuple[float, float]]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as a tuple (connect_timeout, read_timeout).
|
||||
See :meth:`requests.Session.request` documentation for details.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.DataCorruption: If the download's
|
||||
checksum doesn't agree with server-computed checksum.
|
||||
ValueError: If the current :class:`Download` has already
|
||||
finished.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request()
|
||||
# NOTE: We assume "payload is None" but pass it along anyway.
|
||||
result = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
)
|
||||
|
||||
self._process_response(result)
|
||||
|
||||
if self._stream is not None:
|
||||
await self._write_to_stream(result)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
class ChunkedDownload(_request_helpers.RequestsMixin, _download.ChunkedDownload):
|
||||
"""Download a resource in chunks from a Google API.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each
|
||||
request.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
will be used to concatenate chunks of the resource as they are
|
||||
downloaded.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, defaults to ``0``.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, will download to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with each request, e.g. headers for data encryption
|
||||
key headers.
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each request.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``start`` is negative.
|
||||
"""
|
||||
|
||||
async def consume_next_chunk(
|
||||
self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT
|
||||
):
|
||||
|
||||
"""
|
||||
Consume the next chunk of the resource to be downloaded.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
|
||||
Raises:
|
||||
ValueError: If the current download has finished.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request()
|
||||
# NOTE: We assume "payload is None" but pass it along anyway.
|
||||
result = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
|
||||
await self._process_response(result)
|
||||
return result
|
||||
|
||||
|
||||
class RawChunkedDownload(_request_helpers.RawRequestsMixin, _download.ChunkedDownload):
|
||||
"""Download a raw resource in chunks from a Google API.
|
||||
|
||||
Args:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each
|
||||
request.
|
||||
stream (IO[bytes]): A write-able stream (i.e. file-like object) that
|
||||
will be used to concatenate chunks of the resource as they are
|
||||
downloaded.
|
||||
start (int): The first byte in a range to be downloaded. If not
|
||||
provided, defaults to ``0``.
|
||||
end (int): The last byte in a range to be downloaded. If not
|
||||
provided, will download to the end of the media.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with each request, e.g. headers for data encryption
|
||||
key headers.
|
||||
|
||||
Attributes:
|
||||
media_url (str): The URL containing the media to be downloaded.
|
||||
start (Optional[int]): The first byte in a range to be downloaded.
|
||||
end (Optional[int]): The last byte in a range to be downloaded.
|
||||
chunk_size (int): The number of bytes to be retrieved in each request.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``start`` is negative.
|
||||
"""
|
||||
|
||||
async def consume_next_chunk(
|
||||
self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT
|
||||
):
|
||||
"""Consume the next chunk of the resource to be downloaded.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
|
||||
Raises:
|
||||
ValueError: If the current download has finished.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request()
|
||||
# NOTE: We assume "payload is None" but pass it along anyway.
|
||||
result = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
await self._process_response(result)
|
||||
return result
|
||||
|
||||
|
||||
def _add_decoder(response_raw, checksum):
|
||||
"""Patch the ``_decoder`` on a ``urllib3`` response.
|
||||
|
||||
This is so that we can intercept the compressed bytes before they are
|
||||
decoded.
|
||||
|
||||
Only patches if the content encoding is ``gzip``.
|
||||
|
||||
Args:
|
||||
response_raw (urllib3.response.HTTPResponse): The raw response for
|
||||
an HTTP request.
|
||||
checksum (object):
|
||||
A checksum which will be updated with compressed bytes.
|
||||
|
||||
Returns:
|
||||
object: Either the original ``checksum`` if ``_decoder`` is not
|
||||
patched, or a ``_DoNothingHash`` if the decoder is patched, since the
|
||||
caller will no longer need to hash to decoded bytes.
|
||||
"""
|
||||
|
||||
encoding = response_raw.headers.get("content-encoding", "").lower()
|
||||
if encoding != "gzip":
|
||||
return checksum
|
||||
|
||||
response_raw._decoder = _GzipDecoder(checksum)
|
||||
return _helpers._DoNothingHash()
|
||||
|
||||
|
||||
class _GzipDecoder(urllib3.response.GzipDecoder):
|
||||
"""Custom subclass of ``urllib3`` decoder for ``gzip``-ed bytes.
|
||||
|
||||
Allows a checksum function to see the compressed bytes before they are
|
||||
decoded. This way the checksum of the compressed value can be computed.
|
||||
|
||||
Args:
|
||||
checksum (object):
|
||||
A checksum which will be updated with compressed bytes.
|
||||
"""
|
||||
|
||||
def __init__(self, checksum):
|
||||
super(_GzipDecoder, self).__init__()
|
||||
self._checksum = checksum
|
||||
|
||||
def decompress(self, data):
|
||||
"""Decompress the bytes.
|
||||
|
||||
Args:
|
||||
data (bytes): The compressed bytes to be decompressed.
|
||||
|
||||
Returns:
|
||||
bytes: The decompressed bytes from ``data``.
|
||||
"""
|
||||
self._checksum.update(data)
|
||||
return super(_GzipDecoder, self).decompress(data)
|
||||
@@ -0,0 +1,515 @@
|
||||
# Copyright 2017 Google Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""Support for resumable uploads.
|
||||
|
||||
Also supported here are simple (media) uploads and multipart
|
||||
uploads that contain both metadata and a small file as payload.
|
||||
"""
|
||||
|
||||
|
||||
from google._async_resumable_media import _upload
|
||||
from google._async_resumable_media.requests import _request_helpers
|
||||
|
||||
|
||||
class SimpleUpload(_request_helpers.RequestsMixin, _upload.SimpleUpload):
|
||||
"""Upload a resource to a Google API.
|
||||
|
||||
A **simple** media upload sends no metadata and completes the upload
|
||||
in a single request.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
"""
|
||||
|
||||
async def transmit(
|
||||
self,
|
||||
transport,
|
||||
data,
|
||||
content_type,
|
||||
timeout=_request_helpers._DEFAULT_TIMEOUT,
|
||||
):
|
||||
"""Transmit the resource to be uploaded.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
data (bytes): The resource content to be uploaded.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request(data, content_type)
|
||||
|
||||
response = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
self._process_response(response)
|
||||
return response
|
||||
|
||||
|
||||
class MultipartUpload(_request_helpers.RequestsMixin, _upload.MultipartUpload):
|
||||
"""Upload a resource with metadata to a Google API.
|
||||
|
||||
A **multipart** upload sends both metadata and the resource in a single
|
||||
(multipart) request.
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the request, e.g. headers for encrypted data.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. The request metadata will be amended
|
||||
to include the computed value. Using this option will override a
|
||||
manually-set checksum value. Supported values are "md5",
|
||||
"crc32c" and None. The default is None.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
"""
|
||||
|
||||
async def transmit(
|
||||
self,
|
||||
transport,
|
||||
data,
|
||||
metadata,
|
||||
content_type,
|
||||
timeout=_request_helpers._DEFAULT_TIMEOUT,
|
||||
):
|
||||
"""Transmit the resource to be uploaded.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
data (bytes): The resource content to be uploaded.
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request(
|
||||
data, metadata, content_type
|
||||
)
|
||||
|
||||
response = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
self._process_response(response)
|
||||
return response
|
||||
|
||||
|
||||
class ResumableUpload(_request_helpers.RequestsMixin, _upload.ResumableUpload):
|
||||
"""Initiate and fulfill a resumable upload to a Google API.
|
||||
|
||||
A **resumable** upload sends an initial request with the resource metadata
|
||||
and then gets assigned an upload ID / upload URL to send bytes to.
|
||||
Using the upload URL, the upload is then done in chunks (determined by
|
||||
the user) until all bytes have been uploaded.
|
||||
|
||||
When constructing a resumable upload, only the resumable upload URL and
|
||||
the chunk size are required:
|
||||
|
||||
.. testsetup:: resumable-constructor
|
||||
|
||||
bucket = 'bucket-foo'
|
||||
|
||||
.. doctest:: resumable-constructor
|
||||
|
||||
>>> from google.resumable_media.requests import ResumableUpload
|
||||
>>>
|
||||
>>> url_template = (
|
||||
... 'https://www.googleapis.com/upload/storage/v1/b/{bucket}/o?'
|
||||
... 'uploadType=resumable')
|
||||
>>> upload_url = url_template.format(bucket=bucket)
|
||||
>>>
|
||||
>>> chunk_size = 3 * 1024 * 1024 # 3MB
|
||||
>>> upload = ResumableUpload(upload_url, chunk_size)
|
||||
|
||||
When initiating an upload (via :meth:`initiate`), the caller is expected
|
||||
to pass the resource being uploaded as a file-like ``stream``. If the size
|
||||
of the resource is explicitly known, it can be passed in directly:
|
||||
|
||||
.. testsetup:: resumable-explicit-size
|
||||
|
||||
import os
|
||||
import tempfile
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google.resumable_media.requests import ResumableUpload
|
||||
|
||||
upload_url = 'http://test.invalid'
|
||||
chunk_size = 3 * 1024 * 1024 # 3MB
|
||||
upload = ResumableUpload(upload_url, chunk_size)
|
||||
|
||||
file_desc, filename = tempfile.mkstemp()
|
||||
os.close(file_desc)
|
||||
|
||||
data = b'some bytes!'
|
||||
with open(filename, 'wb') as file_obj:
|
||||
file_obj.write(data)
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
fake_response._content = b''
|
||||
resumable_url = 'http://test.invalid?upload_id=7up'
|
||||
fake_response.headers['location'] = resumable_url
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
.. doctest:: resumable-explicit-size
|
||||
|
||||
>>> import os
|
||||
>>>
|
||||
>>> upload.total_bytes is None
|
||||
True
|
||||
>>>
|
||||
>>> stream = open(filename, 'rb')
|
||||
>>> total_bytes = os.path.getsize(filename)
|
||||
>>> metadata = {'name': filename}
|
||||
>>> response = upload.initiate(
|
||||
... transport, stream, metadata, 'text/plain',
|
||||
... total_bytes=total_bytes)
|
||||
>>> response
|
||||
<Response [200]>
|
||||
>>>
|
||||
>>> upload.total_bytes == total_bytes
|
||||
True
|
||||
|
||||
.. testcleanup:: resumable-explicit-size
|
||||
|
||||
os.remove(filename)
|
||||
|
||||
If the stream is in a "final" state (i.e. it won't have any more bytes
|
||||
written to it), the total number of bytes can be determined implicitly
|
||||
from the ``stream`` itself:
|
||||
|
||||
.. testsetup:: resumable-implicit-size
|
||||
|
||||
import io
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google.resumable_media.requests import ResumableUpload
|
||||
|
||||
upload_url = 'http://test.invalid'
|
||||
chunk_size = 3 * 1024 * 1024 # 3MB
|
||||
upload = ResumableUpload(upload_url, chunk_size)
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
fake_response._content = b''
|
||||
resumable_url = 'http://test.invalid?upload_id=7up'
|
||||
fake_response.headers['location'] = resumable_url
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
data = b'some MOAR bytes!'
|
||||
metadata = {'name': 'some-file.jpg'}
|
||||
content_type = 'image/jpeg'
|
||||
|
||||
.. doctest:: resumable-implicit-size
|
||||
|
||||
>>> stream = io.BytesIO(data)
|
||||
>>> response = upload.initiate(
|
||||
... transport, stream, metadata, content_type)
|
||||
>>>
|
||||
>>> upload.total_bytes == len(data)
|
||||
True
|
||||
|
||||
If the size of the resource is **unknown** when the upload is initiated,
|
||||
the ``stream_final`` argument can be used. This might occur if the
|
||||
resource is being dynamically created on the client (e.g. application
|
||||
logs). To use this argument:
|
||||
|
||||
.. testsetup:: resumable-unknown-size
|
||||
|
||||
import io
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google.resumable_media.requests import ResumableUpload
|
||||
|
||||
upload_url = 'http://test.invalid'
|
||||
chunk_size = 3 * 1024 * 1024 # 3MB
|
||||
upload = ResumableUpload(upload_url, chunk_size)
|
||||
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.OK)
|
||||
fake_response._content = b''
|
||||
resumable_url = 'http://test.invalid?upload_id=7up'
|
||||
fake_response.headers['location'] = resumable_url
|
||||
|
||||
post_method = mock.Mock(return_value=fake_response, spec=[])
|
||||
transport = mock.Mock(request=post_method, spec=['request'])
|
||||
|
||||
metadata = {'name': 'some-file.jpg'}
|
||||
content_type = 'application/octet-stream'
|
||||
|
||||
stream = io.BytesIO(b'data')
|
||||
|
||||
.. doctest:: resumable-unknown-size
|
||||
|
||||
>>> response = upload.initiate(
|
||||
... transport, stream, metadata, content_type,
|
||||
... stream_final=False)
|
||||
>>>
|
||||
>>> upload.total_bytes is None
|
||||
True
|
||||
|
||||
Args:
|
||||
upload_url (str): The URL where the resumable upload will be initiated.
|
||||
chunk_size (int): The size of each chunk used to upload the resource.
|
||||
headers (Optional[Mapping[str, str]]): Extra headers that should
|
||||
be sent with the :meth:`initiate` request, e.g. headers for
|
||||
encrypted data. These **will not** be sent with
|
||||
:meth:`transmit_next_chunk` or :meth:`recover` requests.
|
||||
checksum Optional([str]): The type of checksum to compute to verify
|
||||
the integrity of the object. After the upload is complete, the
|
||||
server-computed checksum of the resulting object will be checked
|
||||
and google.resumable_media.common.DataCorruption will be raised on
|
||||
a mismatch. The corrupted file will not be deleted from the remote
|
||||
host automatically. Supported values are "md5", "crc32c" and None.
|
||||
The default is None.
|
||||
|
||||
Attributes:
|
||||
upload_url (str): The URL where the content will be uploaded.
|
||||
|
||||
Raises:
|
||||
ValueError: If ``chunk_size`` is not a multiple of
|
||||
:data:`.UPLOAD_CHUNK_SIZE`.
|
||||
"""
|
||||
|
||||
async def initiate(
|
||||
self,
|
||||
transport,
|
||||
stream,
|
||||
metadata,
|
||||
content_type,
|
||||
total_bytes=None,
|
||||
stream_final=True,
|
||||
timeout=_request_helpers._DEFAULT_TIMEOUT,
|
||||
):
|
||||
"""Initiate a resumable upload.
|
||||
|
||||
By default, this method assumes your ``stream`` is in a "final"
|
||||
state ready to transmit. However, ``stream_final=False`` can be used
|
||||
to indicate that the size of the resource is not known. This can happen
|
||||
if bytes are being dynamically fed into ``stream``, e.g. if the stream
|
||||
is attached to application logs.
|
||||
|
||||
If ``stream_final=False`` is used, :attr:`chunk_size` bytes will be
|
||||
read from the stream every time :meth:`transmit_next_chunk` is called.
|
||||
If one of those reads produces strictly fewer bites than the chunk
|
||||
size, the upload will be concluded.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
stream (IO[bytes]): The stream (i.e. file-like object) that will
|
||||
be uploaded. The stream **must** be at the beginning (i.e.
|
||||
``stream.tell() == 0``).
|
||||
metadata (Mapping[str, str]): The resource metadata, such as an
|
||||
ACL list.
|
||||
content_type (str): The content type of the resource, e.g. a JPEG
|
||||
image has content type ``image/jpeg``.
|
||||
total_bytes (Optional[int]): The total number of bytes to be
|
||||
uploaded. If specified, the upload size **will not** be
|
||||
determined from the stream (even if ``stream_final=True``).
|
||||
stream_final (Optional[bool]): Indicates if the ``stream`` is
|
||||
"final" (i.e. no more bytes will be added to it). In this case
|
||||
we determine the upload size from the size of the stream. If
|
||||
``total_bytes`` is passed, this argument will be ignored.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_initiate_request(
|
||||
stream,
|
||||
metadata,
|
||||
content_type,
|
||||
total_bytes=total_bytes,
|
||||
stream_final=stream_final,
|
||||
)
|
||||
response = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
self._process_initiate_response(response)
|
||||
return response
|
||||
|
||||
async def transmit_next_chunk(
|
||||
self, transport, timeout=_request_helpers._DEFAULT_TIMEOUT
|
||||
):
|
||||
"""Transmit the next chunk of the resource to be uploaded.
|
||||
|
||||
If the current upload was initiated with ``stream_final=False``,
|
||||
this method will dynamically determine if the upload has completed.
|
||||
The upload will be considered complete if the stream produces
|
||||
fewer than :attr:`chunk_size` bytes when a chunk is read from it.
|
||||
|
||||
In the case of failure, an exception is thrown that preserves the
|
||||
failed response:
|
||||
|
||||
.. testsetup:: bad-response
|
||||
|
||||
import io
|
||||
|
||||
import mock
|
||||
import requests
|
||||
import http.client
|
||||
|
||||
from google import resumable_media
|
||||
import google.resumable_media.requests.upload as upload_mod
|
||||
|
||||
transport = mock.Mock(spec=['request'])
|
||||
fake_response = requests.Response()
|
||||
fake_response.status_code = int(http.client.BAD_REQUEST)
|
||||
transport.request.return_value = fake_response
|
||||
|
||||
upload_url = 'http://test.invalid'
|
||||
upload = upload_mod.ResumableUpload(
|
||||
upload_url, resumable_media.UPLOAD_CHUNK_SIZE)
|
||||
# Fake that the upload has been initiate()-d
|
||||
data = b'data is here'
|
||||
upload._stream = io.BytesIO(data)
|
||||
upload._total_bytes = len(data)
|
||||
upload._resumable_url = 'http://test.invalid?upload_id=nope'
|
||||
|
||||
.. doctest:: bad-response
|
||||
:options: +NORMALIZE_WHITESPACE
|
||||
|
||||
>>> error = None
|
||||
>>> try:
|
||||
... upload.transmit_next_chunk(transport)
|
||||
... except resumable_media.InvalidResponse as caught_exc:
|
||||
... error = caught_exc
|
||||
...
|
||||
>>> error
|
||||
InvalidResponse('Request failed with status code', 400,
|
||||
'Expected one of', <HTTPStatus.OK: 200>, 308)
|
||||
>>> error.response
|
||||
<Response [400]>
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
timeout (Optional[Union[float, aiohttp.ClientTimeout]]):
|
||||
The number of seconds to wait for the server response.
|
||||
Depending on the retry strategy, a request may be repeated
|
||||
several times using the same timeout each time.
|
||||
Can also be passed as an `aiohttp.ClientTimeout` object.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
|
||||
Raises:
|
||||
~google.resumable_media.common.InvalidResponse: If the status
|
||||
code is not 200 or 308.
|
||||
~google.resumable_media.common.DataCorruption: If this is the final
|
||||
chunk, a checksum validation was requested, and the checksum
|
||||
does not match or is not available.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_request()
|
||||
response = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
timeout=timeout,
|
||||
)
|
||||
await self._process_resumable_response(response, len(payload))
|
||||
return response
|
||||
|
||||
async def recover(self, transport):
|
||||
"""Recover from a failure.
|
||||
|
||||
This method should be used when a :class:`ResumableUpload` is in an
|
||||
:attr:`~ResumableUpload.invalid` state due to a request failure.
|
||||
|
||||
This will verify the progress with the server and make sure the
|
||||
current upload is in a valid state before :meth:`transmit_next_chunk`
|
||||
can be used again.
|
||||
|
||||
Args:
|
||||
transport (~requests.Session): A ``requests`` object which can
|
||||
make authenticated requests.
|
||||
|
||||
Returns:
|
||||
~requests.Response: The HTTP response returned by ``transport``.
|
||||
"""
|
||||
method, url, payload, headers = self._prepare_recover_request()
|
||||
# NOTE: We assume "payload is None" but pass it along anyway.
|
||||
response = await _request_helpers.http_request(
|
||||
transport,
|
||||
method,
|
||||
url,
|
||||
data=payload,
|
||||
headers=headers,
|
||||
retry_strategy=self._retry_strategy,
|
||||
)
|
||||
self._process_recover_response(response)
|
||||
return response
|
||||
BIN
path/to/venv/lib/python3.12/site-packages/google/_upb/_message.abi3.so
Executable file
BIN
path/to/venv/lib/python3.12/site-packages/google/_upb/_message.abi3.so
Executable file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,31 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/http.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AnnotationsProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// See `HttpRule`.
|
||||
HttpRule http = 72295728;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/annotations.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.api import http_pb2 as google_dot_api_dot_http__pb2
|
||||
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1cgoogle/api/annotations.proto\x12\ngoogle.api\x1a\x15google/api/http.proto\x1a google/protobuf/descriptor.proto:E\n\x04http\x12\x1e.google.protobuf.MethodOptions\x18\xb0\xca\xbc" \x01(\x0b\x32\x14.google.api.HttpRuleBn\n\x0e\x63om.google.apiB\x10\x41nnotationsProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.annotations_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\020AnnotationsProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,23 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
|
||||
from google.api import http_pb2 as _http_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2 as _descriptor_pb2
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
HTTP_FIELD_NUMBER: _ClassVar[int]
|
||||
http: _descriptor.FieldDescriptor
|
||||
237
path/to/venv/lib/python3.12/site-packages/google/api/auth.proto
Normal file
237
path/to/venv/lib/python3.12/site-packages/google/api/auth.proto
Normal file
@@ -0,0 +1,237 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "AuthProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Authentication` defines the authentication configuration for API methods
|
||||
// provided by an API service.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// name: calendar.googleapis.com
|
||||
// authentication:
|
||||
// providers:
|
||||
// - id: google_calendar_auth
|
||||
// jwks_uri: https://www.googleapis.com/oauth2/v1/certs
|
||||
// issuer: https://securetoken.google.com
|
||||
// rules:
|
||||
// - selector: "*"
|
||||
// requirements:
|
||||
// provider_id: google_calendar_auth
|
||||
// - selector: google.calendar.Delegate
|
||||
// oauth:
|
||||
// canonical_scopes: https://www.googleapis.com/auth/calendar.read
|
||||
message Authentication {
|
||||
// A list of authentication rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated AuthenticationRule rules = 3;
|
||||
|
||||
// Defines a set of authentication providers that a service supports.
|
||||
repeated AuthProvider providers = 4;
|
||||
}
|
||||
|
||||
// Authentication rules for the service.
|
||||
//
|
||||
// By default, if a method has any authentication requirements, every request
|
||||
// must include a valid credential matching one of the requirements.
|
||||
// It's an error to include more than one kind of credential in a single
|
||||
// request.
|
||||
//
|
||||
// If a method doesn't have any auth requirements, request credentials will be
|
||||
// ignored.
|
||||
message AuthenticationRule {
|
||||
// Selects the methods to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
|
||||
// details.
|
||||
string selector = 1;
|
||||
|
||||
// The requirements for OAuth credentials.
|
||||
OAuthRequirements oauth = 2;
|
||||
|
||||
// If true, the service accepts API keys without any other credential.
|
||||
// This flag only applies to HTTP and gRPC requests.
|
||||
bool allow_without_credential = 5;
|
||||
|
||||
// Requirements for additional authentication providers.
|
||||
repeated AuthRequirement requirements = 7;
|
||||
}
|
||||
|
||||
// Specifies a location to extract JWT from an API request.
|
||||
message JwtLocation {
|
||||
oneof in {
|
||||
// Specifies HTTP header name to extract JWT token.
|
||||
string header = 1;
|
||||
|
||||
// Specifies URL query parameter name to extract JWT token.
|
||||
string query = 2;
|
||||
|
||||
// Specifies cookie name to extract JWT token.
|
||||
string cookie = 4;
|
||||
}
|
||||
|
||||
// The value prefix. The value format is "value_prefix{token}"
|
||||
// Only applies to "in" header type. Must be empty for "in" query type.
|
||||
// If not empty, the header value has to match (case sensitive) this prefix.
|
||||
// If not matched, JWT will not be extracted. If matched, JWT will be
|
||||
// extracted after the prefix is removed.
|
||||
//
|
||||
// For example, for "Authorization: Bearer {JWT}",
|
||||
// value_prefix="Bearer " with a space at the end.
|
||||
string value_prefix = 3;
|
||||
}
|
||||
|
||||
// Configuration for an authentication provider, including support for
|
||||
// [JSON Web Token
|
||||
// (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32).
|
||||
message AuthProvider {
|
||||
// The unique identifier of the auth provider. It will be referred to by
|
||||
// `AuthRequirement.provider_id`.
|
||||
//
|
||||
// Example: "bookstore_auth".
|
||||
string id = 1;
|
||||
|
||||
// Identifies the principal that issued the JWT. See
|
||||
// https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.1
|
||||
// Usually a URL or an email address.
|
||||
//
|
||||
// Example: https://securetoken.google.com
|
||||
// Example: 1234567-compute@developer.gserviceaccount.com
|
||||
string issuer = 2;
|
||||
|
||||
// URL of the provider's public key set to validate signature of the JWT. See
|
||||
// [OpenID
|
||||
// Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata).
|
||||
// Optional if the key set document:
|
||||
// - can be retrieved from
|
||||
// [OpenID
|
||||
// Discovery](https://openid.net/specs/openid-connect-discovery-1_0.html)
|
||||
// of the issuer.
|
||||
// - can be inferred from the email domain of the issuer (e.g. a Google
|
||||
// service account).
|
||||
//
|
||||
// Example: https://www.googleapis.com/oauth2/v1/certs
|
||||
string jwks_uri = 3;
|
||||
|
||||
// The list of JWT
|
||||
// [audiences](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.3).
|
||||
// that are allowed to access. A JWT containing any of these audiences will
|
||||
// be accepted. When this setting is absent, JWTs with audiences:
|
||||
// - "https://[service.name]/[google.protobuf.Api.name]"
|
||||
// - "https://[service.name]/"
|
||||
// will be accepted.
|
||||
// For example, if no audiences are in the setting, LibraryService API will
|
||||
// accept JWTs with the following audiences:
|
||||
// -
|
||||
// https://library-example.googleapis.com/google.example.library.v1.LibraryService
|
||||
// - https://library-example.googleapis.com/
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// audiences: bookstore_android.apps.googleusercontent.com,
|
||||
// bookstore_web.apps.googleusercontent.com
|
||||
string audiences = 4;
|
||||
|
||||
// Redirect URL if JWT token is required but not present or is expired.
|
||||
// Implement authorizationUrl of securityDefinitions in OpenAPI spec.
|
||||
string authorization_url = 5;
|
||||
|
||||
// Defines the locations to extract the JWT. For now it is only used by the
|
||||
// Cloud Endpoints to store the OpenAPI extension [x-google-jwt-locations]
|
||||
// (https://cloud.google.com/endpoints/docs/openapi/openapi-extensions#x-google-jwt-locations)
|
||||
//
|
||||
// JWT locations can be one of HTTP headers, URL query parameters or
|
||||
// cookies. The rule is that the first match wins.
|
||||
//
|
||||
// If not specified, default to use following 3 locations:
|
||||
// 1) Authorization: Bearer
|
||||
// 2) x-goog-iap-jwt-assertion
|
||||
// 3) access_token query parameter
|
||||
//
|
||||
// Default locations can be specified as followings:
|
||||
// jwt_locations:
|
||||
// - header: Authorization
|
||||
// value_prefix: "Bearer "
|
||||
// - header: x-goog-iap-jwt-assertion
|
||||
// - query: access_token
|
||||
repeated JwtLocation jwt_locations = 6;
|
||||
}
|
||||
|
||||
// OAuth scopes are a way to define data and permissions on data. For example,
|
||||
// there are scopes defined for "Read-only access to Google Calendar" and
|
||||
// "Access to Cloud Platform". Users can consent to a scope for an application,
|
||||
// giving it permission to access that data on their behalf.
|
||||
//
|
||||
// OAuth scope specifications should be fairly coarse grained; a user will need
|
||||
// to see and understand the text description of what your scope means.
|
||||
//
|
||||
// In most cases: use one or at most two OAuth scopes for an entire family of
|
||||
// products. If your product has multiple APIs, you should probably be sharing
|
||||
// the OAuth scope across all of those APIs.
|
||||
//
|
||||
// When you need finer grained OAuth consent screens: talk with your product
|
||||
// management about how developers will use them in practice.
|
||||
//
|
||||
// Please note that even though each of the canonical scopes is enough for a
|
||||
// request to be accepted and passed to the backend, a request can still fail
|
||||
// due to the backend requiring additional scopes or permissions.
|
||||
message OAuthRequirements {
|
||||
// The list of publicly documented OAuth scopes that are allowed access. An
|
||||
// OAuth token containing any of these scopes will be accepted.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// canonical_scopes: https://www.googleapis.com/auth/calendar,
|
||||
// https://www.googleapis.com/auth/calendar.read
|
||||
string canonical_scopes = 1;
|
||||
}
|
||||
|
||||
// User-defined authentication requirements, including support for
|
||||
// [JSON Web Token
|
||||
// (JWT)](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32).
|
||||
message AuthRequirement {
|
||||
// [id][google.api.AuthProvider.id] from authentication provider.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// provider_id: bookstore_auth
|
||||
string provider_id = 1;
|
||||
|
||||
// NOTE: This will be deprecated soon, once AuthProvider.audiences is
|
||||
// implemented and accepted in all the runtime components.
|
||||
//
|
||||
// The list of JWT
|
||||
// [audiences](https://tools.ietf.org/html/draft-ietf-oauth-json-web-token-32#section-4.1.3).
|
||||
// that are allowed to access. A JWT containing any of these audiences will
|
||||
// be accepted. When this setting is absent, only JWTs with audience
|
||||
// "https://[Service_name][google.api.Service.name]/[API_name][google.protobuf.Api.name]"
|
||||
// will be accepted. For example, if no audiences are in the setting,
|
||||
// LibraryService API will only accept JWTs with the following audience
|
||||
// "https://library-example.googleapis.com/google.example.library.v1.LibraryService".
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// audiences: bookstore_android.apps.googleusercontent.com,
|
||||
// bookstore_web.apps.googleusercontent.com
|
||||
string audiences = 2;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/auth.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x15google/api/auth.proto\x12\ngoogle.api"l\n\x0e\x41uthentication\x12-\n\x05rules\x18\x03 \x03(\x0b\x32\x1e.google.api.AuthenticationRule\x12+\n\tproviders\x18\x04 \x03(\x0b\x32\x18.google.api.AuthProvider"\xa9\x01\n\x12\x41uthenticationRule\x12\x10\n\x08selector\x18\x01 \x01(\t\x12,\n\x05oauth\x18\x02 \x01(\x0b\x32\x1d.google.api.OAuthRequirements\x12 \n\x18\x61llow_without_credential\x18\x05 \x01(\x08\x12\x31\n\x0crequirements\x18\x07 \x03(\x0b\x32\x1b.google.api.AuthRequirement"^\n\x0bJwtLocation\x12\x10\n\x06header\x18\x01 \x01(\tH\x00\x12\x0f\n\x05query\x18\x02 \x01(\tH\x00\x12\x10\n\x06\x63ookie\x18\x04 \x01(\tH\x00\x12\x14\n\x0cvalue_prefix\x18\x03 \x01(\tB\x04\n\x02in"\x9a\x01\n\x0c\x41uthProvider\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0e\n\x06issuer\x18\x02 \x01(\t\x12\x10\n\x08jwks_uri\x18\x03 \x01(\t\x12\x11\n\taudiences\x18\x04 \x01(\t\x12\x19\n\x11\x61uthorization_url\x18\x05 \x01(\t\x12.\n\rjwt_locations\x18\x06 \x03(\x0b\x32\x17.google.api.JwtLocation"-\n\x11OAuthRequirements\x12\x18\n\x10\x63\x61nonical_scopes\x18\x01 \x01(\t"9\n\x0f\x41uthRequirement\x12\x13\n\x0bprovider_id\x18\x01 \x01(\t\x12\x11\n\taudiences\x18\x02 \x01(\tBk\n\x0e\x63om.google.apiB\tAuthProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.auth_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\tAuthProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_AUTHENTICATION"]._serialized_start = 37
|
||||
_globals["_AUTHENTICATION"]._serialized_end = 145
|
||||
_globals["_AUTHENTICATIONRULE"]._serialized_start = 148
|
||||
_globals["_AUTHENTICATIONRULE"]._serialized_end = 317
|
||||
_globals["_JWTLOCATION"]._serialized_start = 319
|
||||
_globals["_JWTLOCATION"]._serialized_end = 413
|
||||
_globals["_AUTHPROVIDER"]._serialized_start = 416
|
||||
_globals["_AUTHPROVIDER"]._serialized_end = 570
|
||||
_globals["_OAUTHREQUIREMENTS"]._serialized_start = 572
|
||||
_globals["_OAUTHREQUIREMENTS"]._serialized_end = 617
|
||||
_globals["_AUTHREQUIREMENT"]._serialized_start = 619
|
||||
_globals["_AUTHREQUIREMENT"]._serialized_end = 676
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,120 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Authentication(_message.Message):
|
||||
__slots__ = ("rules", "providers")
|
||||
RULES_FIELD_NUMBER: _ClassVar[int]
|
||||
PROVIDERS_FIELD_NUMBER: _ClassVar[int]
|
||||
rules: _containers.RepeatedCompositeFieldContainer[AuthenticationRule]
|
||||
providers: _containers.RepeatedCompositeFieldContainer[AuthProvider]
|
||||
def __init__(
|
||||
self,
|
||||
rules: _Optional[_Iterable[_Union[AuthenticationRule, _Mapping]]] = ...,
|
||||
providers: _Optional[_Iterable[_Union[AuthProvider, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class AuthenticationRule(_message.Message):
|
||||
__slots__ = ("selector", "oauth", "allow_without_credential", "requirements")
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
OAUTH_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOW_WITHOUT_CREDENTIAL_FIELD_NUMBER: _ClassVar[int]
|
||||
REQUIREMENTS_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
oauth: OAuthRequirements
|
||||
allow_without_credential: bool
|
||||
requirements: _containers.RepeatedCompositeFieldContainer[AuthRequirement]
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
oauth: _Optional[_Union[OAuthRequirements, _Mapping]] = ...,
|
||||
allow_without_credential: bool = ...,
|
||||
requirements: _Optional[_Iterable[_Union[AuthRequirement, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class JwtLocation(_message.Message):
|
||||
__slots__ = ("header", "query", "cookie", "value_prefix")
|
||||
HEADER_FIELD_NUMBER: _ClassVar[int]
|
||||
QUERY_FIELD_NUMBER: _ClassVar[int]
|
||||
COOKIE_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_PREFIX_FIELD_NUMBER: _ClassVar[int]
|
||||
header: str
|
||||
query: str
|
||||
cookie: str
|
||||
value_prefix: str
|
||||
def __init__(
|
||||
self,
|
||||
header: _Optional[str] = ...,
|
||||
query: _Optional[str] = ...,
|
||||
cookie: _Optional[str] = ...,
|
||||
value_prefix: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class AuthProvider(_message.Message):
|
||||
__slots__ = (
|
||||
"id",
|
||||
"issuer",
|
||||
"jwks_uri",
|
||||
"audiences",
|
||||
"authorization_url",
|
||||
"jwt_locations",
|
||||
)
|
||||
ID_FIELD_NUMBER: _ClassVar[int]
|
||||
ISSUER_FIELD_NUMBER: _ClassVar[int]
|
||||
JWKS_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
AUDIENCES_FIELD_NUMBER: _ClassVar[int]
|
||||
AUTHORIZATION_URL_FIELD_NUMBER: _ClassVar[int]
|
||||
JWT_LOCATIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
id: str
|
||||
issuer: str
|
||||
jwks_uri: str
|
||||
audiences: str
|
||||
authorization_url: str
|
||||
jwt_locations: _containers.RepeatedCompositeFieldContainer[JwtLocation]
|
||||
def __init__(
|
||||
self,
|
||||
id: _Optional[str] = ...,
|
||||
issuer: _Optional[str] = ...,
|
||||
jwks_uri: _Optional[str] = ...,
|
||||
audiences: _Optional[str] = ...,
|
||||
authorization_url: _Optional[str] = ...,
|
||||
jwt_locations: _Optional[_Iterable[_Union[JwtLocation, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class OAuthRequirements(_message.Message):
|
||||
__slots__ = ("canonical_scopes",)
|
||||
CANONICAL_SCOPES_FIELD_NUMBER: _ClassVar[int]
|
||||
canonical_scopes: str
|
||||
def __init__(self, canonical_scopes: _Optional[str] = ...) -> None: ...
|
||||
|
||||
class AuthRequirement(_message.Message):
|
||||
__slots__ = ("provider_id", "audiences")
|
||||
PROVIDER_ID_FIELD_NUMBER: _ClassVar[int]
|
||||
AUDIENCES_FIELD_NUMBER: _ClassVar[int]
|
||||
provider_id: str
|
||||
audiences: str
|
||||
def __init__(
|
||||
self, provider_id: _Optional[str] = ..., audiences: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,185 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "BackendProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Backend` defines the backend configuration for a service.
|
||||
message Backend {
|
||||
// A list of API backend rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated BackendRule rules = 1;
|
||||
}
|
||||
|
||||
// A backend rule provides configuration for an individual API element.
|
||||
message BackendRule {
|
||||
// Path Translation specifies how to combine the backend address with the
|
||||
// request path in order to produce the appropriate forwarding URL for the
|
||||
// request.
|
||||
//
|
||||
// Path Translation is applicable only to HTTP-based backends. Backends which
|
||||
// do not accept requests over HTTP/HTTPS should leave `path_translation`
|
||||
// unspecified.
|
||||
enum PathTranslation {
|
||||
PATH_TRANSLATION_UNSPECIFIED = 0;
|
||||
|
||||
// Use the backend address as-is, with no modification to the path. If the
|
||||
// URL pattern contains variables, the variable names and values will be
|
||||
// appended to the query string. If a query string parameter and a URL
|
||||
// pattern variable have the same name, this may result in duplicate keys in
|
||||
// the query string.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Given the following operation config:
|
||||
//
|
||||
// Method path: /api/company/{cid}/user/{uid}
|
||||
// Backend address: https://example.cloudfunctions.net/getUser
|
||||
//
|
||||
// Requests to the following request paths will call the backend at the
|
||||
// translated path:
|
||||
//
|
||||
// Request path: /api/company/widgetworks/user/johndoe
|
||||
// Translated:
|
||||
// https://example.cloudfunctions.net/getUser?cid=widgetworks&uid=johndoe
|
||||
//
|
||||
// Request path: /api/company/widgetworks/user/johndoe?timezone=EST
|
||||
// Translated:
|
||||
// https://example.cloudfunctions.net/getUser?timezone=EST&cid=widgetworks&uid=johndoe
|
||||
CONSTANT_ADDRESS = 1;
|
||||
|
||||
// The request path will be appended to the backend address.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Given the following operation config:
|
||||
//
|
||||
// Method path: /api/company/{cid}/user/{uid}
|
||||
// Backend address: https://example.appspot.com
|
||||
//
|
||||
// Requests to the following request paths will call the backend at the
|
||||
// translated path:
|
||||
//
|
||||
// Request path: /api/company/widgetworks/user/johndoe
|
||||
// Translated:
|
||||
// https://example.appspot.com/api/company/widgetworks/user/johndoe
|
||||
//
|
||||
// Request path: /api/company/widgetworks/user/johndoe?timezone=EST
|
||||
// Translated:
|
||||
// https://example.appspot.com/api/company/widgetworks/user/johndoe?timezone=EST
|
||||
APPEND_PATH_TO_ADDRESS = 2;
|
||||
}
|
||||
|
||||
// Selects the methods to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
|
||||
// details.
|
||||
string selector = 1;
|
||||
|
||||
// The address of the API backend.
|
||||
//
|
||||
// The scheme is used to determine the backend protocol and security.
|
||||
// The following schemes are accepted:
|
||||
//
|
||||
// SCHEME PROTOCOL SECURITY
|
||||
// http:// HTTP None
|
||||
// https:// HTTP TLS
|
||||
// grpc:// gRPC None
|
||||
// grpcs:// gRPC TLS
|
||||
//
|
||||
// It is recommended to explicitly include a scheme. Leaving out the scheme
|
||||
// may cause constrasting behaviors across platforms.
|
||||
//
|
||||
// If the port is unspecified, the default is:
|
||||
// - 80 for schemes without TLS
|
||||
// - 443 for schemes with TLS
|
||||
//
|
||||
// For HTTP backends, use [protocol][google.api.BackendRule.protocol]
|
||||
// to specify the protocol version.
|
||||
string address = 2;
|
||||
|
||||
// The number of seconds to wait for a response from a request. The default
|
||||
// varies based on the request protocol and deployment environment.
|
||||
double deadline = 3;
|
||||
|
||||
// Deprecated, do not use.
|
||||
double min_deadline = 4 [deprecated = true];
|
||||
|
||||
// The number of seconds to wait for the completion of a long running
|
||||
// operation. The default is no deadline.
|
||||
double operation_deadline = 5;
|
||||
|
||||
PathTranslation path_translation = 6;
|
||||
|
||||
// Authentication settings used by the backend.
|
||||
//
|
||||
// These are typically used to provide service management functionality to
|
||||
// a backend served on a publicly-routable URL. The `authentication`
|
||||
// details should match the authentication behavior used by the backend.
|
||||
//
|
||||
// For example, specifying `jwt_audience` implies that the backend expects
|
||||
// authentication via a JWT.
|
||||
//
|
||||
// When authentication is unspecified, the resulting behavior is the same
|
||||
// as `disable_auth` set to `true`.
|
||||
//
|
||||
// Refer to https://developers.google.com/identity/protocols/OpenIDConnect for
|
||||
// JWT ID token.
|
||||
oneof authentication {
|
||||
// The JWT audience is used when generating a JWT ID token for the backend.
|
||||
// This ID token will be added in the HTTP "authorization" header, and sent
|
||||
// to the backend.
|
||||
string jwt_audience = 7;
|
||||
|
||||
// When disable_auth is true, a JWT ID token won't be generated and the
|
||||
// original "Authorization" HTTP header will be preserved. If the header is
|
||||
// used to carry the original token and is expected by the backend, this
|
||||
// field must be set to true to preserve the header.
|
||||
bool disable_auth = 8;
|
||||
}
|
||||
|
||||
// The protocol used for sending a request to the backend.
|
||||
// The supported values are "http/1.1" and "h2".
|
||||
//
|
||||
// The default value is inferred from the scheme in the
|
||||
// [address][google.api.BackendRule.address] field:
|
||||
//
|
||||
// SCHEME PROTOCOL
|
||||
// http:// http/1.1
|
||||
// https:// http/1.1
|
||||
// grpc:// h2
|
||||
// grpcs:// h2
|
||||
//
|
||||
// For secure HTTP backends (https://) that support HTTP/2, set this field
|
||||
// to "h2" for improved performance.
|
||||
//
|
||||
// Configuring this field to non-default values is only supported for secure
|
||||
// HTTP backends. This field will be ignored for all other backends.
|
||||
//
|
||||
// See
|
||||
// https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids
|
||||
// for more details on the supported values.
|
||||
string protocol = 9;
|
||||
|
||||
// The map between request protocol and the backend address.
|
||||
map<string, BackendRule> overrides_by_request_protocol = 10;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/backend.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x18google/api/backend.proto\x12\ngoogle.api"1\n\x07\x42\x61\x63kend\x12&\n\x05rules\x18\x01 \x03(\x0b\x32\x17.google.api.BackendRule"\xb2\x04\n\x0b\x42\x61\x63kendRule\x12\x10\n\x08selector\x18\x01 \x01(\t\x12\x0f\n\x07\x61\x64\x64ress\x18\x02 \x01(\t\x12\x10\n\x08\x64\x65\x61\x64line\x18\x03 \x01(\x01\x12\x18\n\x0cmin_deadline\x18\x04 \x01(\x01\x42\x02\x18\x01\x12\x1a\n\x12operation_deadline\x18\x05 \x01(\x01\x12\x41\n\x10path_translation\x18\x06 \x01(\x0e\x32\'.google.api.BackendRule.PathTranslation\x12\x16\n\x0cjwt_audience\x18\x07 \x01(\tH\x00\x12\x16\n\x0c\x64isable_auth\x18\x08 \x01(\x08H\x00\x12\x10\n\x08protocol\x18\t \x01(\t\x12^\n\x1doverrides_by_request_protocol\x18\n \x03(\x0b\x32\x37.google.api.BackendRule.OverridesByRequestProtocolEntry\x1aZ\n\x1fOverridesByRequestProtocolEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12&\n\x05value\x18\x02 \x01(\x0b\x32\x17.google.api.BackendRule:\x02\x38\x01"e\n\x0fPathTranslation\x12 \n\x1cPATH_TRANSLATION_UNSPECIFIED\x10\x00\x12\x14\n\x10\x43ONSTANT_ADDRESS\x10\x01\x12\x1a\n\x16\x41PPEND_PATH_TO_ADDRESS\x10\x02\x42\x10\n\x0e\x61uthenticationBn\n\x0e\x63om.google.apiB\x0c\x42\x61\x63kendProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.backend_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\014BackendProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"]._options = None
|
||||
_globals[
|
||||
"_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"
|
||||
]._serialized_options = b"8\001"
|
||||
_globals["_BACKENDRULE"].fields_by_name["min_deadline"]._options = None
|
||||
_globals["_BACKENDRULE"].fields_by_name[
|
||||
"min_deadline"
|
||||
]._serialized_options = b"\030\001"
|
||||
_globals["_BACKEND"]._serialized_start = 40
|
||||
_globals["_BACKEND"]._serialized_end = 89
|
||||
_globals["_BACKENDRULE"]._serialized_start = 92
|
||||
_globals["_BACKENDRULE"]._serialized_end = 654
|
||||
_globals["_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"]._serialized_start = 443
|
||||
_globals["_BACKENDRULE_OVERRIDESBYREQUESTPROTOCOLENTRY"]._serialized_end = 533
|
||||
_globals["_BACKENDRULE_PATHTRANSLATION"]._serialized_start = 535
|
||||
_globals["_BACKENDRULE_PATHTRANSLATION"]._serialized_end = 636
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,102 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Backend(_message.Message):
|
||||
__slots__ = ("rules",)
|
||||
RULES_FIELD_NUMBER: _ClassVar[int]
|
||||
rules: _containers.RepeatedCompositeFieldContainer[BackendRule]
|
||||
def __init__(
|
||||
self, rules: _Optional[_Iterable[_Union[BackendRule, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class BackendRule(_message.Message):
|
||||
__slots__ = (
|
||||
"selector",
|
||||
"address",
|
||||
"deadline",
|
||||
"min_deadline",
|
||||
"operation_deadline",
|
||||
"path_translation",
|
||||
"jwt_audience",
|
||||
"disable_auth",
|
||||
"protocol",
|
||||
"overrides_by_request_protocol",
|
||||
)
|
||||
|
||||
class PathTranslation(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
PATH_TRANSLATION_UNSPECIFIED: _ClassVar[BackendRule.PathTranslation]
|
||||
CONSTANT_ADDRESS: _ClassVar[BackendRule.PathTranslation]
|
||||
APPEND_PATH_TO_ADDRESS: _ClassVar[BackendRule.PathTranslation]
|
||||
PATH_TRANSLATION_UNSPECIFIED: BackendRule.PathTranslation
|
||||
CONSTANT_ADDRESS: BackendRule.PathTranslation
|
||||
APPEND_PATH_TO_ADDRESS: BackendRule.PathTranslation
|
||||
|
||||
class OverridesByRequestProtocolEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: BackendRule
|
||||
def __init__(
|
||||
self,
|
||||
key: _Optional[str] = ...,
|
||||
value: _Optional[_Union[BackendRule, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
ADDRESS_FIELD_NUMBER: _ClassVar[int]
|
||||
DEADLINE_FIELD_NUMBER: _ClassVar[int]
|
||||
MIN_DEADLINE_FIELD_NUMBER: _ClassVar[int]
|
||||
OPERATION_DEADLINE_FIELD_NUMBER: _ClassVar[int]
|
||||
PATH_TRANSLATION_FIELD_NUMBER: _ClassVar[int]
|
||||
JWT_AUDIENCE_FIELD_NUMBER: _ClassVar[int]
|
||||
DISABLE_AUTH_FIELD_NUMBER: _ClassVar[int]
|
||||
PROTOCOL_FIELD_NUMBER: _ClassVar[int]
|
||||
OVERRIDES_BY_REQUEST_PROTOCOL_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
address: str
|
||||
deadline: float
|
||||
min_deadline: float
|
||||
operation_deadline: float
|
||||
path_translation: BackendRule.PathTranslation
|
||||
jwt_audience: str
|
||||
disable_auth: bool
|
||||
protocol: str
|
||||
overrides_by_request_protocol: _containers.MessageMap[str, BackendRule]
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
address: _Optional[str] = ...,
|
||||
deadline: _Optional[float] = ...,
|
||||
min_deadline: _Optional[float] = ...,
|
||||
operation_deadline: _Optional[float] = ...,
|
||||
path_translation: _Optional[_Union[BackendRule.PathTranslation, str]] = ...,
|
||||
jwt_audience: _Optional[str] = ...,
|
||||
disable_auth: bool = ...,
|
||||
protocol: _Optional[str] = ...,
|
||||
overrides_by_request_protocol: _Optional[_Mapping[str, BackendRule]] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "BillingProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Billing related configuration of the service.
|
||||
//
|
||||
// The following example shows how to configure monitored resources and metrics
|
||||
// for billing, `consumer_destinations` is the only supported destination and
|
||||
// the monitored resources need at least one label key
|
||||
// `cloud.googleapis.com/location` to indicate the location of the billing
|
||||
// usage, using different monitored resources between monitoring and billing is
|
||||
// recommended so they can be evolved independently:
|
||||
//
|
||||
//
|
||||
// monitored_resources:
|
||||
// - type: library.googleapis.com/billing_branch
|
||||
// labels:
|
||||
// - key: cloud.googleapis.com/location
|
||||
// description: |
|
||||
// Predefined label to support billing location restriction.
|
||||
// - key: city
|
||||
// description: |
|
||||
// Custom label to define the city where the library branch is located
|
||||
// in.
|
||||
// - key: name
|
||||
// description: Custom label to define the name of the library branch.
|
||||
// metrics:
|
||||
// - name: library.googleapis.com/book/borrowed_count
|
||||
// metric_kind: DELTA
|
||||
// value_type: INT64
|
||||
// unit: "1"
|
||||
// billing:
|
||||
// consumer_destinations:
|
||||
// - monitored_resource: library.googleapis.com/billing_branch
|
||||
// metrics:
|
||||
// - library.googleapis.com/book/borrowed_count
|
||||
message Billing {
|
||||
// Configuration of a specific billing destination (Currently only support
|
||||
// bill against consumer project).
|
||||
message BillingDestination {
|
||||
// The monitored resource type. The type must be defined in
|
||||
// [Service.monitored_resources][google.api.Service.monitored_resources]
|
||||
// section.
|
||||
string monitored_resource = 1;
|
||||
|
||||
// Names of the metrics to report to this billing destination.
|
||||
// Each name must be defined in
|
||||
// [Service.metrics][google.api.Service.metrics] section.
|
||||
repeated string metrics = 2;
|
||||
}
|
||||
|
||||
// Billing configurations for sending metrics to the consumer project.
|
||||
// There can be multiple consumer destinations per service, each one must have
|
||||
// a different monitored resource type. A metric can be used in at most
|
||||
// one consumer destination.
|
||||
repeated BillingDestination consumer_destinations = 8;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/billing.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x18google/api/billing.proto\x12\ngoogle.api"\x93\x01\n\x07\x42illing\x12\x45\n\x15\x63onsumer_destinations\x18\x08 \x03(\x0b\x32&.google.api.Billing.BillingDestination\x1a\x41\n\x12\x42illingDestination\x12\x1a\n\x12monitored_resource\x18\x01 \x01(\t\x12\x0f\n\x07metrics\x18\x02 \x03(\tBn\n\x0e\x63om.google.apiB\x0c\x42illingProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.billing_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\014BillingProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_BILLING"]._serialized_start = 41
|
||||
_globals["_BILLING"]._serialized_end = 188
|
||||
_globals["_BILLING_BILLINGDESTINATION"]._serialized_start = 123
|
||||
_globals["_BILLING_BILLINGDESTINATION"]._serialized_end = 188
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,50 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Billing(_message.Message):
|
||||
__slots__ = ("consumer_destinations",)
|
||||
|
||||
class BillingDestination(_message.Message):
|
||||
__slots__ = ("monitored_resource", "metrics")
|
||||
MONITORED_RESOURCE_FIELD_NUMBER: _ClassVar[int]
|
||||
METRICS_FIELD_NUMBER: _ClassVar[int]
|
||||
monitored_resource: str
|
||||
metrics: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(
|
||||
self,
|
||||
monitored_resource: _Optional[str] = ...,
|
||||
metrics: _Optional[_Iterable[str]] = ...,
|
||||
) -> None: ...
|
||||
CONSUMER_DESTINATIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
consumer_destinations: _containers.RepeatedCompositeFieldContainer[
|
||||
Billing.BillingDestination
|
||||
]
|
||||
def __init__(
|
||||
self,
|
||||
consumer_destinations: _Optional[
|
||||
_Iterable[_Union[Billing.BillingDestination, _Mapping]]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,486 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/launch_stage.proto";
|
||||
import "google/protobuf/descriptor.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ClientProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.MethodOptions {
|
||||
// A definition of a client library method signature.
|
||||
//
|
||||
// In client libraries, each proto RPC corresponds to one or more methods
|
||||
// which the end user is able to call, and calls the underlying RPC.
|
||||
// Normally, this method receives a single argument (a struct or instance
|
||||
// corresponding to the RPC request object). Defining this field will
|
||||
// add one or more overloads providing flattened or simpler method signatures
|
||||
// in some languages.
|
||||
//
|
||||
// The fields on the method signature are provided as a comma-separated
|
||||
// string.
|
||||
//
|
||||
// For example, the proto RPC and annotation:
|
||||
//
|
||||
// rpc CreateSubscription(CreateSubscriptionRequest)
|
||||
// returns (Subscription) {
|
||||
// option (google.api.method_signature) = "name,topic";
|
||||
// }
|
||||
//
|
||||
// Would add the following Java overload (in addition to the method accepting
|
||||
// the request object):
|
||||
//
|
||||
// public final Subscription createSubscription(String name, String topic)
|
||||
//
|
||||
// The following backwards-compatibility guidelines apply:
|
||||
//
|
||||
// * Adding this annotation to an unannotated method is backwards
|
||||
// compatible.
|
||||
// * Adding this annotation to a method which already has existing
|
||||
// method signature annotations is backwards compatible if and only if
|
||||
// the new method signature annotation is last in the sequence.
|
||||
// * Modifying or removing an existing method signature annotation is
|
||||
// a breaking change.
|
||||
// * Re-ordering existing method signature annotations is a breaking
|
||||
// change.
|
||||
repeated string method_signature = 1051;
|
||||
}
|
||||
|
||||
extend google.protobuf.ServiceOptions {
|
||||
// The hostname for this service.
|
||||
// This should be specified with no prefix or protocol.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Foo {
|
||||
// option (google.api.default_host) = "foo.googleapi.com";
|
||||
// ...
|
||||
// }
|
||||
string default_host = 1049;
|
||||
|
||||
// OAuth scopes needed for the client.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Foo {
|
||||
// option (google.api.oauth_scopes) = \
|
||||
// "https://www.googleapis.com/auth/cloud-platform";
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// If there is more than one scope, use a comma-separated string:
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Foo {
|
||||
// option (google.api.oauth_scopes) = \
|
||||
// "https://www.googleapis.com/auth/cloud-platform,"
|
||||
// "https://www.googleapis.com/auth/monitoring";
|
||||
// ...
|
||||
// }
|
||||
string oauth_scopes = 1050;
|
||||
|
||||
// The API version of this service, which should be sent by version-aware
|
||||
// clients to the service. This allows services to abide by the schema and
|
||||
// behavior of the service at the time this API version was deployed.
|
||||
// The format of the API version must be treated as opaque by clients.
|
||||
// Services may use a format with an apparent structure, but clients must
|
||||
// not rely on this to determine components within an API version, or attempt
|
||||
// to construct other valid API versions. Note that this is for upcoming
|
||||
// functionality and may not be implemented for all services.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Foo {
|
||||
// option (google.api.api_version) = "v1_20230821_preview";
|
||||
// }
|
||||
string api_version = 525000001;
|
||||
}
|
||||
|
||||
// Required information for every language.
|
||||
message CommonLanguageSettings {
|
||||
// Link to automatically generated reference documentation. Example:
|
||||
// https://cloud.google.com/nodejs/docs/reference/asset/latest
|
||||
string reference_docs_uri = 1 [deprecated = true];
|
||||
|
||||
// The destination where API teams want this client library to be published.
|
||||
repeated ClientLibraryDestination destinations = 2;
|
||||
|
||||
// Configuration for which RPCs should be generated in the GAPIC client.
|
||||
SelectiveGapicGeneration selective_gapic_generation = 3;
|
||||
}
|
||||
|
||||
// Details about how and where to publish client libraries.
|
||||
message ClientLibrarySettings {
|
||||
// Version of the API to apply these settings to. This is the full protobuf
|
||||
// package for the API, ending in the version element.
|
||||
// Examples: "google.cloud.speech.v1" and "google.spanner.admin.database.v1".
|
||||
string version = 1;
|
||||
|
||||
// Launch stage of this version of the API.
|
||||
LaunchStage launch_stage = 2;
|
||||
|
||||
// When using transport=rest, the client request will encode enums as
|
||||
// numbers rather than strings.
|
||||
bool rest_numeric_enums = 3;
|
||||
|
||||
// Settings for legacy Java features, supported in the Service YAML.
|
||||
JavaSettings java_settings = 21;
|
||||
|
||||
// Settings for C++ client libraries.
|
||||
CppSettings cpp_settings = 22;
|
||||
|
||||
// Settings for PHP client libraries.
|
||||
PhpSettings php_settings = 23;
|
||||
|
||||
// Settings for Python client libraries.
|
||||
PythonSettings python_settings = 24;
|
||||
|
||||
// Settings for Node client libraries.
|
||||
NodeSettings node_settings = 25;
|
||||
|
||||
// Settings for .NET client libraries.
|
||||
DotnetSettings dotnet_settings = 26;
|
||||
|
||||
// Settings for Ruby client libraries.
|
||||
RubySettings ruby_settings = 27;
|
||||
|
||||
// Settings for Go client libraries.
|
||||
GoSettings go_settings = 28;
|
||||
}
|
||||
|
||||
// This message configures the settings for publishing [Google Cloud Client
|
||||
// libraries](https://cloud.google.com/apis/docs/cloud-client-libraries)
|
||||
// generated from the service config.
|
||||
message Publishing {
|
||||
// A list of API method settings, e.g. the behavior for methods that use the
|
||||
// long-running operation pattern.
|
||||
repeated MethodSettings method_settings = 2;
|
||||
|
||||
// Link to a *public* URI where users can report issues. Example:
|
||||
// https://issuetracker.google.com/issues/new?component=190865&template=1161103
|
||||
string new_issue_uri = 101;
|
||||
|
||||
// Link to product home page. Example:
|
||||
// https://cloud.google.com/asset-inventory/docs/overview
|
||||
string documentation_uri = 102;
|
||||
|
||||
// Used as a tracking tag when collecting data about the APIs developer
|
||||
// relations artifacts like docs, packages delivered to package managers,
|
||||
// etc. Example: "speech".
|
||||
string api_short_name = 103;
|
||||
|
||||
// GitHub label to apply to issues and pull requests opened for this API.
|
||||
string github_label = 104;
|
||||
|
||||
// GitHub teams to be added to CODEOWNERS in the directory in GitHub
|
||||
// containing source code for the client libraries for this API.
|
||||
repeated string codeowner_github_teams = 105;
|
||||
|
||||
// A prefix used in sample code when demarking regions to be included in
|
||||
// documentation.
|
||||
string doc_tag_prefix = 106;
|
||||
|
||||
// For whom the client library is being published.
|
||||
ClientLibraryOrganization organization = 107;
|
||||
|
||||
// Client library settings. If the same version string appears multiple
|
||||
// times in this list, then the last one wins. Settings from earlier
|
||||
// settings with the same version string are discarded.
|
||||
repeated ClientLibrarySettings library_settings = 109;
|
||||
|
||||
// Optional link to proto reference documentation. Example:
|
||||
// https://cloud.google.com/pubsub/lite/docs/reference/rpc
|
||||
string proto_reference_documentation_uri = 110;
|
||||
|
||||
// Optional link to REST reference documentation. Example:
|
||||
// https://cloud.google.com/pubsub/lite/docs/reference/rest
|
||||
string rest_reference_documentation_uri = 111;
|
||||
}
|
||||
|
||||
// Settings for Java client libraries.
|
||||
message JavaSettings {
|
||||
// The package name to use in Java. Clobbers the java_package option
|
||||
// set in the protobuf. This should be used **only** by APIs
|
||||
// who have already set the language_settings.java.package_name" field
|
||||
// in gapic.yaml. API teams should use the protobuf java_package option
|
||||
// where possible.
|
||||
//
|
||||
// Example of a YAML configuration::
|
||||
//
|
||||
// publishing:
|
||||
// java_settings:
|
||||
// library_package: com.google.cloud.pubsub.v1
|
||||
string library_package = 1;
|
||||
|
||||
// Configure the Java class name to use instead of the service's for its
|
||||
// corresponding generated GAPIC client. Keys are fully-qualified
|
||||
// service names as they appear in the protobuf (including the full
|
||||
// the language_settings.java.interface_names" field in gapic.yaml. API
|
||||
// teams should otherwise use the service name as it appears in the
|
||||
// protobuf.
|
||||
//
|
||||
// Example of a YAML configuration::
|
||||
//
|
||||
// publishing:
|
||||
// java_settings:
|
||||
// service_class_names:
|
||||
// - google.pubsub.v1.Publisher: TopicAdmin
|
||||
// - google.pubsub.v1.Subscriber: SubscriptionAdmin
|
||||
map<string, string> service_class_names = 2;
|
||||
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 3;
|
||||
}
|
||||
|
||||
// Settings for C++ client libraries.
|
||||
message CppSettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
}
|
||||
|
||||
// Settings for Php client libraries.
|
||||
message PhpSettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
}
|
||||
|
||||
// Settings for Python client libraries.
|
||||
message PythonSettings {
|
||||
// Experimental features to be included during client library generation.
|
||||
// These fields will be deprecated once the feature graduates and is enabled
|
||||
// by default.
|
||||
message ExperimentalFeatures {
|
||||
// Enables generation of asynchronous REST clients if `rest` transport is
|
||||
// enabled. By default, asynchronous REST clients will not be generated.
|
||||
// This feature will be enabled by default 1 month after launching the
|
||||
// feature in preview packages.
|
||||
bool rest_async_io_enabled = 1;
|
||||
|
||||
// Enables generation of protobuf code using new types that are more
|
||||
// Pythonic which are included in `protobuf>=5.29.x`. This feature will be
|
||||
// enabled by default 1 month after launching the feature in preview
|
||||
// packages.
|
||||
bool protobuf_pythonic_types_enabled = 2;
|
||||
|
||||
// Disables generation of an unversioned Python package for this client
|
||||
// library. This means that the module names will need to be versioned in
|
||||
// import statements. For example `import google.cloud.library_v2` instead
|
||||
// of `import google.cloud.library`.
|
||||
bool unversioned_package_disabled = 3;
|
||||
}
|
||||
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
|
||||
// Experimental features to be included during client library generation.
|
||||
ExperimentalFeatures experimental_features = 2;
|
||||
}
|
||||
|
||||
// Settings for Node client libraries.
|
||||
message NodeSettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
}
|
||||
|
||||
// Settings for Dotnet client libraries.
|
||||
message DotnetSettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
|
||||
// Map from original service names to renamed versions.
|
||||
// This is used when the default generated types
|
||||
// would cause a naming conflict. (Neither name is
|
||||
// fully-qualified.)
|
||||
// Example: Subscriber to SubscriberServiceApi.
|
||||
map<string, string> renamed_services = 2;
|
||||
|
||||
// Map from full resource types to the effective short name
|
||||
// for the resource. This is used when otherwise resource
|
||||
// named from different services would cause naming collisions.
|
||||
// Example entry:
|
||||
// "datalabeling.googleapis.com/Dataset": "DataLabelingDataset"
|
||||
map<string, string> renamed_resources = 3;
|
||||
|
||||
// List of full resource types to ignore during generation.
|
||||
// This is typically used for API-specific Location resources,
|
||||
// which should be handled by the generator as if they were actually
|
||||
// the common Location resources.
|
||||
// Example entry: "documentai.googleapis.com/Location"
|
||||
repeated string ignored_resources = 4;
|
||||
|
||||
// Namespaces which must be aliased in snippets due to
|
||||
// a known (but non-generator-predictable) naming collision
|
||||
repeated string forced_namespace_aliases = 5;
|
||||
|
||||
// Method signatures (in the form "service.method(signature)")
|
||||
// which are provided separately, so shouldn't be generated.
|
||||
// Snippets *calling* these methods are still generated, however.
|
||||
repeated string handwritten_signatures = 6;
|
||||
}
|
||||
|
||||
// Settings for Ruby client libraries.
|
||||
message RubySettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
}
|
||||
|
||||
// Settings for Go client libraries.
|
||||
message GoSettings {
|
||||
// Some settings.
|
||||
CommonLanguageSettings common = 1;
|
||||
|
||||
// Map of service names to renamed services. Keys are the package relative
|
||||
// service names and values are the name to be used for the service client
|
||||
// and call options.
|
||||
//
|
||||
// publishing:
|
||||
// go_settings:
|
||||
// renamed_services:
|
||||
// Publisher: TopicAdmin
|
||||
map<string, string> renamed_services = 2;
|
||||
}
|
||||
|
||||
// Describes the generator configuration for a method.
|
||||
message MethodSettings {
|
||||
// Describes settings to use when generating API methods that use the
|
||||
// long-running operation pattern.
|
||||
// All default values below are from those used in the client library
|
||||
// generators (e.g.
|
||||
// [Java](https://github.com/googleapis/gapic-generator-java/blob/04c2faa191a9b5a10b92392fe8482279c4404803/src/main/java/com/google/api/generator/gapic/composer/common/RetrySettingsComposer.java)).
|
||||
message LongRunning {
|
||||
// Initial delay after which the first poll request will be made.
|
||||
// Default value: 5 seconds.
|
||||
google.protobuf.Duration initial_poll_delay = 1;
|
||||
|
||||
// Multiplier to gradually increase delay between subsequent polls until it
|
||||
// reaches max_poll_delay.
|
||||
// Default value: 1.5.
|
||||
float poll_delay_multiplier = 2;
|
||||
|
||||
// Maximum time between two subsequent poll requests.
|
||||
// Default value: 45 seconds.
|
||||
google.protobuf.Duration max_poll_delay = 3;
|
||||
|
||||
// Total polling timeout.
|
||||
// Default value: 5 minutes.
|
||||
google.protobuf.Duration total_poll_timeout = 4;
|
||||
}
|
||||
|
||||
// The fully qualified name of the method, for which the options below apply.
|
||||
// This is used to find the method to apply the options.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// publishing:
|
||||
// method_settings:
|
||||
// - selector: google.storage.control.v2.StorageControl.CreateFolder
|
||||
// # method settings for CreateFolder...
|
||||
string selector = 1;
|
||||
|
||||
// Describes settings to use for long-running operations when generating
|
||||
// API methods for RPCs. Complements RPCs that use the annotations in
|
||||
// google/longrunning/operations.proto.
|
||||
//
|
||||
// Example of a YAML configuration::
|
||||
//
|
||||
// publishing:
|
||||
// method_settings:
|
||||
// - selector: google.cloud.speech.v2.Speech.BatchRecognize
|
||||
// long_running:
|
||||
// initial_poll_delay: 60s # 1 minute
|
||||
// poll_delay_multiplier: 1.5
|
||||
// max_poll_delay: 360s # 6 minutes
|
||||
// total_poll_timeout: 54000s # 90 minutes
|
||||
LongRunning long_running = 2;
|
||||
|
||||
// List of top-level fields of the request message, that should be
|
||||
// automatically populated by the client libraries based on their
|
||||
// (google.api.field_info).format. Currently supported format: UUID4.
|
||||
//
|
||||
// Example of a YAML configuration:
|
||||
//
|
||||
// publishing:
|
||||
// method_settings:
|
||||
// - selector: google.example.v1.ExampleService.CreateExample
|
||||
// auto_populated_fields:
|
||||
// - request_id
|
||||
repeated string auto_populated_fields = 3;
|
||||
}
|
||||
|
||||
// The organization for which the client libraries are being published.
|
||||
// Affects the url where generated docs are published, etc.
|
||||
enum ClientLibraryOrganization {
|
||||
// Not useful.
|
||||
CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED = 0;
|
||||
|
||||
// Google Cloud Platform Org.
|
||||
CLOUD = 1;
|
||||
|
||||
// Ads (Advertising) Org.
|
||||
ADS = 2;
|
||||
|
||||
// Photos Org.
|
||||
PHOTOS = 3;
|
||||
|
||||
// Street View Org.
|
||||
STREET_VIEW = 4;
|
||||
|
||||
// Shopping Org.
|
||||
SHOPPING = 5;
|
||||
|
||||
// Geo Org.
|
||||
GEO = 6;
|
||||
|
||||
// Generative AI - https://developers.generativeai.google
|
||||
GENERATIVE_AI = 7;
|
||||
}
|
||||
|
||||
// To where should client libraries be published?
|
||||
enum ClientLibraryDestination {
|
||||
// Client libraries will neither be generated nor published to package
|
||||
// managers.
|
||||
CLIENT_LIBRARY_DESTINATION_UNSPECIFIED = 0;
|
||||
|
||||
// Generate the client library in a repo under github.com/googleapis,
|
||||
// but don't publish it to package managers.
|
||||
GITHUB = 10;
|
||||
|
||||
// Publish the library to package managers like nuget.org and npmjs.com.
|
||||
PACKAGE_MANAGER = 20;
|
||||
}
|
||||
|
||||
// This message is used to configure the generation of a subset of the RPCs in
|
||||
// a service for client libraries.
|
||||
message SelectiveGapicGeneration {
|
||||
// An allowlist of the fully qualified names of RPCs that should be included
|
||||
// on public client surfaces.
|
||||
repeated string methods = 1;
|
||||
|
||||
// Setting this to true indicates to the client generators that methods
|
||||
// that would be excluded from the generation should instead be generated
|
||||
// in a way that indicates these methods should not be consumed by
|
||||
// end users. How this is expressed is up to individual language
|
||||
// implementations to decide. Some examples may be: added annotations,
|
||||
// obfuscated identifiers, or other language idiomatic patterns.
|
||||
bool generate_omitted_as_internal = 2;
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,404 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.api import launch_stage_pb2 as _launch_stage_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2 as _descriptor_pb2
|
||||
from google.protobuf import duration_pb2 as _duration_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class ClientLibraryOrganization(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED: _ClassVar[ClientLibraryOrganization]
|
||||
CLOUD: _ClassVar[ClientLibraryOrganization]
|
||||
ADS: _ClassVar[ClientLibraryOrganization]
|
||||
PHOTOS: _ClassVar[ClientLibraryOrganization]
|
||||
STREET_VIEW: _ClassVar[ClientLibraryOrganization]
|
||||
SHOPPING: _ClassVar[ClientLibraryOrganization]
|
||||
GEO: _ClassVar[ClientLibraryOrganization]
|
||||
GENERATIVE_AI: _ClassVar[ClientLibraryOrganization]
|
||||
|
||||
class ClientLibraryDestination(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
CLIENT_LIBRARY_DESTINATION_UNSPECIFIED: _ClassVar[ClientLibraryDestination]
|
||||
GITHUB: _ClassVar[ClientLibraryDestination]
|
||||
PACKAGE_MANAGER: _ClassVar[ClientLibraryDestination]
|
||||
|
||||
CLIENT_LIBRARY_ORGANIZATION_UNSPECIFIED: ClientLibraryOrganization
|
||||
CLOUD: ClientLibraryOrganization
|
||||
ADS: ClientLibraryOrganization
|
||||
PHOTOS: ClientLibraryOrganization
|
||||
STREET_VIEW: ClientLibraryOrganization
|
||||
SHOPPING: ClientLibraryOrganization
|
||||
GEO: ClientLibraryOrganization
|
||||
GENERATIVE_AI: ClientLibraryOrganization
|
||||
CLIENT_LIBRARY_DESTINATION_UNSPECIFIED: ClientLibraryDestination
|
||||
GITHUB: ClientLibraryDestination
|
||||
PACKAGE_MANAGER: ClientLibraryDestination
|
||||
METHOD_SIGNATURE_FIELD_NUMBER: _ClassVar[int]
|
||||
method_signature: _descriptor.FieldDescriptor
|
||||
DEFAULT_HOST_FIELD_NUMBER: _ClassVar[int]
|
||||
default_host: _descriptor.FieldDescriptor
|
||||
OAUTH_SCOPES_FIELD_NUMBER: _ClassVar[int]
|
||||
oauth_scopes: _descriptor.FieldDescriptor
|
||||
API_VERSION_FIELD_NUMBER: _ClassVar[int]
|
||||
api_version: _descriptor.FieldDescriptor
|
||||
|
||||
class CommonLanguageSettings(_message.Message):
|
||||
__slots__ = ("reference_docs_uri", "destinations", "selective_gapic_generation")
|
||||
REFERENCE_DOCS_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
DESTINATIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
SELECTIVE_GAPIC_GENERATION_FIELD_NUMBER: _ClassVar[int]
|
||||
reference_docs_uri: str
|
||||
destinations: _containers.RepeatedScalarFieldContainer[ClientLibraryDestination]
|
||||
selective_gapic_generation: SelectiveGapicGeneration
|
||||
def __init__(
|
||||
self,
|
||||
reference_docs_uri: _Optional[str] = ...,
|
||||
destinations: _Optional[_Iterable[_Union[ClientLibraryDestination, str]]] = ...,
|
||||
selective_gapic_generation: _Optional[
|
||||
_Union[SelectiveGapicGeneration, _Mapping]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class ClientLibrarySettings(_message.Message):
|
||||
__slots__ = (
|
||||
"version",
|
||||
"launch_stage",
|
||||
"rest_numeric_enums",
|
||||
"java_settings",
|
||||
"cpp_settings",
|
||||
"php_settings",
|
||||
"python_settings",
|
||||
"node_settings",
|
||||
"dotnet_settings",
|
||||
"ruby_settings",
|
||||
"go_settings",
|
||||
)
|
||||
VERSION_FIELD_NUMBER: _ClassVar[int]
|
||||
LAUNCH_STAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
REST_NUMERIC_ENUMS_FIELD_NUMBER: _ClassVar[int]
|
||||
JAVA_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
CPP_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
PHP_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
PYTHON_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
NODE_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
DOTNET_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
RUBY_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
GO_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
version: str
|
||||
launch_stage: _launch_stage_pb2.LaunchStage
|
||||
rest_numeric_enums: bool
|
||||
java_settings: JavaSettings
|
||||
cpp_settings: CppSettings
|
||||
php_settings: PhpSettings
|
||||
python_settings: PythonSettings
|
||||
node_settings: NodeSettings
|
||||
dotnet_settings: DotnetSettings
|
||||
ruby_settings: RubySettings
|
||||
go_settings: GoSettings
|
||||
def __init__(
|
||||
self,
|
||||
version: _Optional[str] = ...,
|
||||
launch_stage: _Optional[_Union[_launch_stage_pb2.LaunchStage, str]] = ...,
|
||||
rest_numeric_enums: bool = ...,
|
||||
java_settings: _Optional[_Union[JavaSettings, _Mapping]] = ...,
|
||||
cpp_settings: _Optional[_Union[CppSettings, _Mapping]] = ...,
|
||||
php_settings: _Optional[_Union[PhpSettings, _Mapping]] = ...,
|
||||
python_settings: _Optional[_Union[PythonSettings, _Mapping]] = ...,
|
||||
node_settings: _Optional[_Union[NodeSettings, _Mapping]] = ...,
|
||||
dotnet_settings: _Optional[_Union[DotnetSettings, _Mapping]] = ...,
|
||||
ruby_settings: _Optional[_Union[RubySettings, _Mapping]] = ...,
|
||||
go_settings: _Optional[_Union[GoSettings, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Publishing(_message.Message):
|
||||
__slots__ = (
|
||||
"method_settings",
|
||||
"new_issue_uri",
|
||||
"documentation_uri",
|
||||
"api_short_name",
|
||||
"github_label",
|
||||
"codeowner_github_teams",
|
||||
"doc_tag_prefix",
|
||||
"organization",
|
||||
"library_settings",
|
||||
"proto_reference_documentation_uri",
|
||||
"rest_reference_documentation_uri",
|
||||
)
|
||||
METHOD_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
NEW_ISSUE_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
DOCUMENTATION_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
API_SHORT_NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
GITHUB_LABEL_FIELD_NUMBER: _ClassVar[int]
|
||||
CODEOWNER_GITHUB_TEAMS_FIELD_NUMBER: _ClassVar[int]
|
||||
DOC_TAG_PREFIX_FIELD_NUMBER: _ClassVar[int]
|
||||
ORGANIZATION_FIELD_NUMBER: _ClassVar[int]
|
||||
LIBRARY_SETTINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
PROTO_REFERENCE_DOCUMENTATION_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
REST_REFERENCE_DOCUMENTATION_URI_FIELD_NUMBER: _ClassVar[int]
|
||||
method_settings: _containers.RepeatedCompositeFieldContainer[MethodSettings]
|
||||
new_issue_uri: str
|
||||
documentation_uri: str
|
||||
api_short_name: str
|
||||
github_label: str
|
||||
codeowner_github_teams: _containers.RepeatedScalarFieldContainer[str]
|
||||
doc_tag_prefix: str
|
||||
organization: ClientLibraryOrganization
|
||||
library_settings: _containers.RepeatedCompositeFieldContainer[ClientLibrarySettings]
|
||||
proto_reference_documentation_uri: str
|
||||
rest_reference_documentation_uri: str
|
||||
def __init__(
|
||||
self,
|
||||
method_settings: _Optional[_Iterable[_Union[MethodSettings, _Mapping]]] = ...,
|
||||
new_issue_uri: _Optional[str] = ...,
|
||||
documentation_uri: _Optional[str] = ...,
|
||||
api_short_name: _Optional[str] = ...,
|
||||
github_label: _Optional[str] = ...,
|
||||
codeowner_github_teams: _Optional[_Iterable[str]] = ...,
|
||||
doc_tag_prefix: _Optional[str] = ...,
|
||||
organization: _Optional[_Union[ClientLibraryOrganization, str]] = ...,
|
||||
library_settings: _Optional[
|
||||
_Iterable[_Union[ClientLibrarySettings, _Mapping]]
|
||||
] = ...,
|
||||
proto_reference_documentation_uri: _Optional[str] = ...,
|
||||
rest_reference_documentation_uri: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class JavaSettings(_message.Message):
|
||||
__slots__ = ("library_package", "service_class_names", "common")
|
||||
|
||||
class ServiceClassNamesEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
LIBRARY_PACKAGE_FIELD_NUMBER: _ClassVar[int]
|
||||
SERVICE_CLASS_NAMES_FIELD_NUMBER: _ClassVar[int]
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
library_package: str
|
||||
service_class_names: _containers.ScalarMap[str, str]
|
||||
common: CommonLanguageSettings
|
||||
def __init__(
|
||||
self,
|
||||
library_package: _Optional[str] = ...,
|
||||
service_class_names: _Optional[_Mapping[str, str]] = ...,
|
||||
common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class CppSettings(_message.Message):
|
||||
__slots__ = ("common",)
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
def __init__(
|
||||
self, common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class PhpSettings(_message.Message):
|
||||
__slots__ = ("common",)
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
def __init__(
|
||||
self, common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class PythonSettings(_message.Message):
|
||||
__slots__ = ("common", "experimental_features")
|
||||
|
||||
class ExperimentalFeatures(_message.Message):
|
||||
__slots__ = (
|
||||
"rest_async_io_enabled",
|
||||
"protobuf_pythonic_types_enabled",
|
||||
"unversioned_package_disabled",
|
||||
)
|
||||
REST_ASYNC_IO_ENABLED_FIELD_NUMBER: _ClassVar[int]
|
||||
PROTOBUF_PYTHONIC_TYPES_ENABLED_FIELD_NUMBER: _ClassVar[int]
|
||||
UNVERSIONED_PACKAGE_DISABLED_FIELD_NUMBER: _ClassVar[int]
|
||||
rest_async_io_enabled: bool
|
||||
protobuf_pythonic_types_enabled: bool
|
||||
unversioned_package_disabled: bool
|
||||
def __init__(
|
||||
self,
|
||||
rest_async_io_enabled: bool = ...,
|
||||
protobuf_pythonic_types_enabled: bool = ...,
|
||||
unversioned_package_disabled: bool = ...,
|
||||
) -> None: ...
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
EXPERIMENTAL_FEATURES_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
experimental_features: PythonSettings.ExperimentalFeatures
|
||||
def __init__(
|
||||
self,
|
||||
common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...,
|
||||
experimental_features: _Optional[
|
||||
_Union[PythonSettings.ExperimentalFeatures, _Mapping]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class NodeSettings(_message.Message):
|
||||
__slots__ = ("common",)
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
def __init__(
|
||||
self, common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class DotnetSettings(_message.Message):
|
||||
__slots__ = (
|
||||
"common",
|
||||
"renamed_services",
|
||||
"renamed_resources",
|
||||
"ignored_resources",
|
||||
"forced_namespace_aliases",
|
||||
"handwritten_signatures",
|
||||
)
|
||||
|
||||
class RenamedServicesEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
|
||||
class RenamedResourcesEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
RENAMED_SERVICES_FIELD_NUMBER: _ClassVar[int]
|
||||
RENAMED_RESOURCES_FIELD_NUMBER: _ClassVar[int]
|
||||
IGNORED_RESOURCES_FIELD_NUMBER: _ClassVar[int]
|
||||
FORCED_NAMESPACE_ALIASES_FIELD_NUMBER: _ClassVar[int]
|
||||
HANDWRITTEN_SIGNATURES_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
renamed_services: _containers.ScalarMap[str, str]
|
||||
renamed_resources: _containers.ScalarMap[str, str]
|
||||
ignored_resources: _containers.RepeatedScalarFieldContainer[str]
|
||||
forced_namespace_aliases: _containers.RepeatedScalarFieldContainer[str]
|
||||
handwritten_signatures: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(
|
||||
self,
|
||||
common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...,
|
||||
renamed_services: _Optional[_Mapping[str, str]] = ...,
|
||||
renamed_resources: _Optional[_Mapping[str, str]] = ...,
|
||||
ignored_resources: _Optional[_Iterable[str]] = ...,
|
||||
forced_namespace_aliases: _Optional[_Iterable[str]] = ...,
|
||||
handwritten_signatures: _Optional[_Iterable[str]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class RubySettings(_message.Message):
|
||||
__slots__ = ("common",)
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
def __init__(
|
||||
self, common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class GoSettings(_message.Message):
|
||||
__slots__ = ("common", "renamed_services")
|
||||
|
||||
class RenamedServicesEntry(_message.Message):
|
||||
__slots__ = ("key", "value")
|
||||
KEY_FIELD_NUMBER: _ClassVar[int]
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
key: str
|
||||
value: str
|
||||
def __init__(
|
||||
self, key: _Optional[str] = ..., value: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
COMMON_FIELD_NUMBER: _ClassVar[int]
|
||||
RENAMED_SERVICES_FIELD_NUMBER: _ClassVar[int]
|
||||
common: CommonLanguageSettings
|
||||
renamed_services: _containers.ScalarMap[str, str]
|
||||
def __init__(
|
||||
self,
|
||||
common: _Optional[_Union[CommonLanguageSettings, _Mapping]] = ...,
|
||||
renamed_services: _Optional[_Mapping[str, str]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class MethodSettings(_message.Message):
|
||||
__slots__ = ("selector", "long_running", "auto_populated_fields")
|
||||
|
||||
class LongRunning(_message.Message):
|
||||
__slots__ = (
|
||||
"initial_poll_delay",
|
||||
"poll_delay_multiplier",
|
||||
"max_poll_delay",
|
||||
"total_poll_timeout",
|
||||
)
|
||||
INITIAL_POLL_DELAY_FIELD_NUMBER: _ClassVar[int]
|
||||
POLL_DELAY_MULTIPLIER_FIELD_NUMBER: _ClassVar[int]
|
||||
MAX_POLL_DELAY_FIELD_NUMBER: _ClassVar[int]
|
||||
TOTAL_POLL_TIMEOUT_FIELD_NUMBER: _ClassVar[int]
|
||||
initial_poll_delay: _duration_pb2.Duration
|
||||
poll_delay_multiplier: float
|
||||
max_poll_delay: _duration_pb2.Duration
|
||||
total_poll_timeout: _duration_pb2.Duration
|
||||
def __init__(
|
||||
self,
|
||||
initial_poll_delay: _Optional[
|
||||
_Union[_duration_pb2.Duration, _Mapping]
|
||||
] = ...,
|
||||
poll_delay_multiplier: _Optional[float] = ...,
|
||||
max_poll_delay: _Optional[_Union[_duration_pb2.Duration, _Mapping]] = ...,
|
||||
total_poll_timeout: _Optional[
|
||||
_Union[_duration_pb2.Duration, _Mapping]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
LONG_RUNNING_FIELD_NUMBER: _ClassVar[int]
|
||||
AUTO_POPULATED_FIELDS_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
long_running: MethodSettings.LongRunning
|
||||
auto_populated_fields: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
long_running: _Optional[_Union[MethodSettings.LongRunning, _Mapping]] = ...,
|
||||
auto_populated_fields: _Optional[_Iterable[str]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class SelectiveGapicGeneration(_message.Message):
|
||||
__slots__ = ("methods", "generate_omitted_as_internal")
|
||||
METHODS_FIELD_NUMBER: _ClassVar[int]
|
||||
GENERATE_OMITTED_AS_INTERNAL_FIELD_NUMBER: _ClassVar[int]
|
||||
methods: _containers.RepeatedScalarFieldContainer[str]
|
||||
generate_omitted_as_internal: bool
|
||||
def __init__(
|
||||
self,
|
||||
methods: _Optional[_Iterable[str]] = ...,
|
||||
generate_omitted_as_internal: bool = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/configchange;configchange";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ConfigChangeProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Output generated from semantically comparing two versions of a service
|
||||
// configuration.
|
||||
//
|
||||
// Includes detailed information about a field that have changed with
|
||||
// applicable advice about potential consequences for the change, such as
|
||||
// backwards-incompatibility.
|
||||
message ConfigChange {
|
||||
// Object hierarchy path to the change, with levels separated by a '.'
|
||||
// character. For repeated fields, an applicable unique identifier field is
|
||||
// used for the index (usually selector, name, or id). For maps, the term
|
||||
// 'key' is used. If the field has no unique identifier, the numeric index
|
||||
// is used.
|
||||
// Examples:
|
||||
// - visibility.rules[selector=="google.LibraryService.ListBooks"].restriction
|
||||
// - quota.metric_rules[selector=="google"].metric_costs[key=="reads"].value
|
||||
// - logging.producer_destinations[0]
|
||||
string element = 1;
|
||||
|
||||
// Value of the changed object in the old Service configuration,
|
||||
// in JSON format. This field will not be populated if ChangeType == ADDED.
|
||||
string old_value = 2;
|
||||
|
||||
// Value of the changed object in the new Service configuration,
|
||||
// in JSON format. This field will not be populated if ChangeType == REMOVED.
|
||||
string new_value = 3;
|
||||
|
||||
// The type for this change, either ADDED, REMOVED, or MODIFIED.
|
||||
ChangeType change_type = 4;
|
||||
|
||||
// Collection of advice provided for this change, useful for determining the
|
||||
// possible impact of this change.
|
||||
repeated Advice advices = 5;
|
||||
}
|
||||
|
||||
// Generated advice about this change, used for providing more
|
||||
// information about how a change will affect the existing service.
|
||||
message Advice {
|
||||
// Useful description for why this advice was applied and what actions should
|
||||
// be taken to mitigate any implied risks.
|
||||
string description = 2;
|
||||
}
|
||||
|
||||
// Classifies set of possible modifications to an object in the service
|
||||
// configuration.
|
||||
enum ChangeType {
|
||||
// No value was provided.
|
||||
CHANGE_TYPE_UNSPECIFIED = 0;
|
||||
|
||||
// The changed object exists in the 'new' service configuration, but not
|
||||
// in the 'old' service configuration.
|
||||
ADDED = 1;
|
||||
|
||||
// The changed object exists in the 'old' service configuration, but not
|
||||
// in the 'new' service configuration.
|
||||
REMOVED = 2;
|
||||
|
||||
// The changed object exists in both service configurations, but its value
|
||||
// is different.
|
||||
MODIFIED = 3;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/config_change.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1egoogle/api/config_change.proto\x12\ngoogle.api"\x97\x01\n\x0c\x43onfigChange\x12\x0f\n\x07\x65lement\x18\x01 \x01(\t\x12\x11\n\told_value\x18\x02 \x01(\t\x12\x11\n\tnew_value\x18\x03 \x01(\t\x12+\n\x0b\x63hange_type\x18\x04 \x01(\x0e\x32\x16.google.api.ChangeType\x12#\n\x07\x61\x64vices\x18\x05 \x03(\x0b\x32\x12.google.api.Advice"\x1d\n\x06\x41\x64vice\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t*O\n\nChangeType\x12\x1b\n\x17\x43HANGE_TYPE_UNSPECIFIED\x10\x00\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x01\x12\x0b\n\x07REMOVED\x10\x02\x12\x0c\n\x08MODIFIED\x10\x03\x42q\n\x0e\x63om.google.apiB\x11\x43onfigChangeProtoP\x01ZCgoogle.golang.org/genproto/googleapis/api/configchange;configchange\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.config_change_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\021ConfigChangeProtoP\001ZCgoogle.golang.org/genproto/googleapis/api/configchange;configchange\242\002\004GAPI"
|
||||
_globals["_CHANGETYPE"]._serialized_start = 231
|
||||
_globals["_CHANGETYPE"]._serialized_end = 310
|
||||
_globals["_CONFIGCHANGE"]._serialized_start = 47
|
||||
_globals["_CONFIGCHANGE"]._serialized_end = 198
|
||||
_globals["_ADVICE"]._serialized_start = 200
|
||||
_globals["_ADVICE"]._serialized_end = 229
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,65 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class ChangeType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
CHANGE_TYPE_UNSPECIFIED: _ClassVar[ChangeType]
|
||||
ADDED: _ClassVar[ChangeType]
|
||||
REMOVED: _ClassVar[ChangeType]
|
||||
MODIFIED: _ClassVar[ChangeType]
|
||||
|
||||
CHANGE_TYPE_UNSPECIFIED: ChangeType
|
||||
ADDED: ChangeType
|
||||
REMOVED: ChangeType
|
||||
MODIFIED: ChangeType
|
||||
|
||||
class ConfigChange(_message.Message):
|
||||
__slots__ = ("element", "old_value", "new_value", "change_type", "advices")
|
||||
ELEMENT_FIELD_NUMBER: _ClassVar[int]
|
||||
OLD_VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
NEW_VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
CHANGE_TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
ADVICES_FIELD_NUMBER: _ClassVar[int]
|
||||
element: str
|
||||
old_value: str
|
||||
new_value: str
|
||||
change_type: ChangeType
|
||||
advices: _containers.RepeatedCompositeFieldContainer[Advice]
|
||||
def __init__(
|
||||
self,
|
||||
element: _Optional[str] = ...,
|
||||
old_value: _Optional[str] = ...,
|
||||
new_value: _Optional[str] = ...,
|
||||
change_type: _Optional[_Union[ChangeType, str]] = ...,
|
||||
advices: _Optional[_Iterable[_Union[Advice, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Advice(_message.Message):
|
||||
__slots__ = ("description",)
|
||||
DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
|
||||
description: str
|
||||
def __init__(self, description: _Optional[str] = ...) -> None: ...
|
||||
@@ -0,0 +1,82 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ConsumerProto";
|
||||
option java_package = "com.google.api";
|
||||
|
||||
// A descriptor for defining project properties for a service. One service may
|
||||
// have many consumer projects, and the service may want to behave differently
|
||||
// depending on some properties on the project. For example, a project may be
|
||||
// associated with a school, or a business, or a government agency, a business
|
||||
// type property on the project may affect how a service responds to the client.
|
||||
// This descriptor defines which properties are allowed to be set on a project.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// project_properties:
|
||||
// properties:
|
||||
// - name: NO_WATERMARK
|
||||
// type: BOOL
|
||||
// description: Allows usage of the API without watermarks.
|
||||
// - name: EXTENDED_TILE_CACHE_PERIOD
|
||||
// type: INT64
|
||||
message ProjectProperties {
|
||||
// List of per consumer project-specific properties.
|
||||
repeated Property properties = 1;
|
||||
}
|
||||
|
||||
// Defines project properties.
|
||||
//
|
||||
// API services can define properties that can be assigned to consumer projects
|
||||
// so that backends can perform response customization without having to make
|
||||
// additional calls or maintain additional storage. For example, Maps API
|
||||
// defines properties that controls map tile cache period, or whether to embed a
|
||||
// watermark in a result.
|
||||
//
|
||||
// These values can be set via API producer console. Only API providers can
|
||||
// define and set these properties.
|
||||
message Property {
|
||||
// Supported data type of the property values
|
||||
enum PropertyType {
|
||||
// The type is unspecified, and will result in an error.
|
||||
UNSPECIFIED = 0;
|
||||
|
||||
// The type is `int64`.
|
||||
INT64 = 1;
|
||||
|
||||
// The type is `bool`.
|
||||
BOOL = 2;
|
||||
|
||||
// The type is `string`.
|
||||
STRING = 3;
|
||||
|
||||
// The type is 'double'.
|
||||
DOUBLE = 4;
|
||||
}
|
||||
|
||||
// The name of the property (a.k.a key).
|
||||
string name = 1;
|
||||
|
||||
// The type of this property.
|
||||
PropertyType type = 2;
|
||||
|
||||
// The description of the property
|
||||
string description = 3;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/consumer.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x19google/api/consumer.proto\x12\ngoogle.api"=\n\x11ProjectProperties\x12(\n\nproperties\x18\x01 \x03(\x0b\x32\x14.google.api.Property"\xac\x01\n\x08Property\x12\x0c\n\x04name\x18\x01 \x01(\t\x12/\n\x04type\x18\x02 \x01(\x0e\x32!.google.api.Property.PropertyType\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t"L\n\x0cPropertyType\x12\x0f\n\x0bUNSPECIFIED\x10\x00\x12\t\n\x05INT64\x10\x01\x12\x08\n\x04\x42OOL\x10\x02\x12\n\n\x06STRING\x10\x03\x12\n\n\x06\x44OUBLE\x10\x04\x42h\n\x0e\x63om.google.apiB\rConsumerProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfigb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.consumer_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\rConsumerProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig"
|
||||
_globals["_PROJECTPROPERTIES"]._serialized_start = 41
|
||||
_globals["_PROJECTPROPERTIES"]._serialized_end = 102
|
||||
_globals["_PROPERTY"]._serialized_start = 105
|
||||
_globals["_PROPERTY"]._serialized_end = 277
|
||||
_globals["_PROPERTY_PROPERTYTYPE"]._serialized_start = 201
|
||||
_globals["_PROPERTY_PROPERTYTYPE"]._serialized_end = 277
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,62 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class ProjectProperties(_message.Message):
|
||||
__slots__ = ("properties",)
|
||||
PROPERTIES_FIELD_NUMBER: _ClassVar[int]
|
||||
properties: _containers.RepeatedCompositeFieldContainer[Property]
|
||||
def __init__(
|
||||
self, properties: _Optional[_Iterable[_Union[Property, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class Property(_message.Message):
|
||||
__slots__ = ("name", "type", "description")
|
||||
|
||||
class PropertyType(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
UNSPECIFIED: _ClassVar[Property.PropertyType]
|
||||
INT64: _ClassVar[Property.PropertyType]
|
||||
BOOL: _ClassVar[Property.PropertyType]
|
||||
STRING: _ClassVar[Property.PropertyType]
|
||||
DOUBLE: _ClassVar[Property.PropertyType]
|
||||
UNSPECIFIED: Property.PropertyType
|
||||
INT64: Property.PropertyType
|
||||
BOOL: Property.PropertyType
|
||||
STRING: Property.PropertyType
|
||||
DOUBLE: Property.PropertyType
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
TYPE_FIELD_NUMBER: _ClassVar[int]
|
||||
DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
type: Property.PropertyType
|
||||
description: str
|
||||
def __init__(
|
||||
self,
|
||||
name: _Optional[str] = ...,
|
||||
type: _Optional[_Union[Property.PropertyType, str]] = ...,
|
||||
description: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,92 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ContextProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Context` defines which contexts an API requests.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// context:
|
||||
// rules:
|
||||
// - selector: "*"
|
||||
// requested:
|
||||
// - google.rpc.context.ProjectContext
|
||||
// - google.rpc.context.OriginContext
|
||||
//
|
||||
// The above specifies that all methods in the API request
|
||||
// `google.rpc.context.ProjectContext` and
|
||||
// `google.rpc.context.OriginContext`.
|
||||
//
|
||||
// Available context types are defined in package
|
||||
// `google.rpc.context`.
|
||||
//
|
||||
// This also provides mechanism to allowlist any protobuf message extension that
|
||||
// can be sent in grpc metadata using “x-goog-ext-<extension_id>-bin” and
|
||||
// “x-goog-ext-<extension_id>-jspb” format. For example, list any service
|
||||
// specific protobuf types that can appear in grpc metadata as follows in your
|
||||
// yaml file:
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// context:
|
||||
// rules:
|
||||
// - selector: "google.example.library.v1.LibraryService.CreateBook"
|
||||
// allowed_request_extensions:
|
||||
// - google.foo.v1.NewExtension
|
||||
// allowed_response_extensions:
|
||||
// - google.foo.v1.NewExtension
|
||||
//
|
||||
// You can also specify extension ID instead of fully qualified extension name
|
||||
// here.
|
||||
message Context {
|
||||
// A list of RPC context rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated ContextRule rules = 1;
|
||||
}
|
||||
|
||||
// A context rule provides information about the context for an individual API
|
||||
// element.
|
||||
message ContextRule {
|
||||
// Selects the methods to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
|
||||
// details.
|
||||
string selector = 1;
|
||||
|
||||
// A list of full type names of requested contexts, only the requested context
|
||||
// will be made available to the backend.
|
||||
repeated string requested = 2;
|
||||
|
||||
// A list of full type names of provided contexts. It is used to support
|
||||
// propagating HTTP headers and ETags from the response extension.
|
||||
repeated string provided = 3;
|
||||
|
||||
// A list of full type names or extension IDs of extensions allowed in grpc
|
||||
// side channel from client to backend.
|
||||
repeated string allowed_request_extensions = 4;
|
||||
|
||||
// A list of full type names or extension IDs of extensions allowed in grpc
|
||||
// side channel from backend to client.
|
||||
repeated string allowed_response_extensions = 5;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/context.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x18google/api/context.proto\x12\ngoogle.api"1\n\x07\x43ontext\x12&\n\x05rules\x18\x01 \x03(\x0b\x32\x17.google.api.ContextRule"\x8d\x01\n\x0b\x43ontextRule\x12\x10\n\x08selector\x18\x01 \x01(\t\x12\x11\n\trequested\x18\x02 \x03(\t\x12\x10\n\x08provided\x18\x03 \x03(\t\x12"\n\x1a\x61llowed_request_extensions\x18\x04 \x03(\t\x12#\n\x1b\x61llowed_response_extensions\x18\x05 \x03(\tBn\n\x0e\x63om.google.apiB\x0c\x43ontextProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.context_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\014ContextProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_CONTEXT"]._serialized_start = 40
|
||||
_globals["_CONTEXT"]._serialized_end = 89
|
||||
_globals["_CONTEXTRULE"]._serialized_start = 92
|
||||
_globals["_CONTEXTRULE"]._serialized_end = 233
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Context(_message.Message):
|
||||
__slots__ = ("rules",)
|
||||
RULES_FIELD_NUMBER: _ClassVar[int]
|
||||
rules: _containers.RepeatedCompositeFieldContainer[ContextRule]
|
||||
def __init__(
|
||||
self, rules: _Optional[_Iterable[_Union[ContextRule, _Mapping]]] = ...
|
||||
) -> None: ...
|
||||
|
||||
class ContextRule(_message.Message):
|
||||
__slots__ = (
|
||||
"selector",
|
||||
"requested",
|
||||
"provided",
|
||||
"allowed_request_extensions",
|
||||
"allowed_response_extensions",
|
||||
)
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
REQUESTED_FIELD_NUMBER: _ClassVar[int]
|
||||
PROVIDED_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOWED_REQUEST_EXTENSIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOWED_RESPONSE_EXTENSIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
requested: _containers.RepeatedScalarFieldContainer[str]
|
||||
provided: _containers.RepeatedScalarFieldContainer[str]
|
||||
allowed_request_extensions: _containers.RepeatedScalarFieldContainer[str]
|
||||
allowed_response_extensions: _containers.RepeatedScalarFieldContainer[str]
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
requested: _Optional[_Iterable[str]] = ...,
|
||||
provided: _Optional[_Iterable[str]] = ...,
|
||||
allowed_request_extensions: _Optional[_Iterable[str]] = ...,
|
||||
allowed_response_extensions: _Optional[_Iterable[str]] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,41 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/api/policy.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ControlProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Selects and configures the service controller used by the service.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// control:
|
||||
// environment: servicecontrol.googleapis.com
|
||||
message Control {
|
||||
// The service controller environment to use. If empty, no control plane
|
||||
// feature (like quota and billing) will be enabled. The recommended value for
|
||||
// most services is servicecontrol.googleapis.com
|
||||
string environment = 1;
|
||||
|
||||
// Defines policies applying to the API methods of the service.
|
||||
repeated MethodPolicy method_policies = 4;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/control.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.api import policy_pb2 as google_dot_api_dot_policy__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x18google/api/control.proto\x12\ngoogle.api\x1a\x17google/api/policy.proto"Q\n\x07\x43ontrol\x12\x13\n\x0b\x65nvironment\x18\x01 \x01(\t\x12\x31\n\x0fmethod_policies\x18\x04 \x03(\x0b\x32\x18.google.api.MethodPolicyBn\n\x0e\x63om.google.apiB\x0c\x43ontrolProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.control_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\014ControlProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_CONTROL"]._serialized_start = 65
|
||||
_globals["_CONTROL"]._serialized_end = 146
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,42 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.api import policy_pb2 as _policy_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Control(_message.Message):
|
||||
__slots__ = ("environment", "method_policies")
|
||||
ENVIRONMENT_FIELD_NUMBER: _ClassVar[int]
|
||||
METHOD_POLICIES_FIELD_NUMBER: _ClassVar[int]
|
||||
environment: str
|
||||
method_policies: _containers.RepeatedCompositeFieldContainer[
|
||||
_policy_pb2.MethodPolicy
|
||||
]
|
||||
def __init__(
|
||||
self,
|
||||
environment: _Optional[str] = ...,
|
||||
method_policies: _Optional[
|
||||
_Iterable[_Union[_policy_pb2.MethodPolicy, _Mapping]]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,213 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/distribution;distribution";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "DistributionProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Distribution` contains summary statistics for a population of values. It
|
||||
// optionally contains a histogram representing the distribution of those values
|
||||
// across a set of buckets.
|
||||
//
|
||||
// The summary statistics are the count, mean, sum of the squared deviation from
|
||||
// the mean, the minimum, and the maximum of the set of population of values.
|
||||
// The histogram is based on a sequence of buckets and gives a count of values
|
||||
// that fall into each bucket. The boundaries of the buckets are given either
|
||||
// explicitly or by formulas for buckets of fixed or exponentially increasing
|
||||
// widths.
|
||||
//
|
||||
// Although it is not forbidden, it is generally a bad idea to include
|
||||
// non-finite values (infinities or NaNs) in the population of values, as this
|
||||
// will render the `mean` and `sum_of_squared_deviation` fields meaningless.
|
||||
message Distribution {
|
||||
// The range of the population values.
|
||||
message Range {
|
||||
// The minimum of the population values.
|
||||
double min = 1;
|
||||
|
||||
// The maximum of the population values.
|
||||
double max = 2;
|
||||
}
|
||||
|
||||
// `BucketOptions` describes the bucket boundaries used to create a histogram
|
||||
// for the distribution. The buckets can be in a linear sequence, an
|
||||
// exponential sequence, or each bucket can be specified explicitly.
|
||||
// `BucketOptions` does not include the number of values in each bucket.
|
||||
//
|
||||
// A bucket has an inclusive lower bound and exclusive upper bound for the
|
||||
// values that are counted for that bucket. The upper bound of a bucket must
|
||||
// be strictly greater than the lower bound. The sequence of N buckets for a
|
||||
// distribution consists of an underflow bucket (number 0), zero or more
|
||||
// finite buckets (number 1 through N - 2) and an overflow bucket (number N -
|
||||
// 1). The buckets are contiguous: the lower bound of bucket i (i > 0) is the
|
||||
// same as the upper bound of bucket i - 1. The buckets span the whole range
|
||||
// of finite values: lower bound of the underflow bucket is -infinity and the
|
||||
// upper bound of the overflow bucket is +infinity. The finite buckets are
|
||||
// so-called because both bounds are finite.
|
||||
message BucketOptions {
|
||||
// Specifies a linear sequence of buckets that all have the same width
|
||||
// (except overflow and underflow). Each bucket represents a constant
|
||||
// absolute uncertainty on the specific value in the bucket.
|
||||
//
|
||||
// There are `num_finite_buckets + 2` (= N) buckets. Bucket `i` has the
|
||||
// following boundaries:
|
||||
//
|
||||
// Upper bound (0 <= i < N-1): offset + (width * i).
|
||||
//
|
||||
// Lower bound (1 <= i < N): offset + (width * (i - 1)).
|
||||
message Linear {
|
||||
// Must be greater than 0.
|
||||
int32 num_finite_buckets = 1;
|
||||
|
||||
// Must be greater than 0.
|
||||
double width = 2;
|
||||
|
||||
// Lower bound of the first bucket.
|
||||
double offset = 3;
|
||||
}
|
||||
|
||||
// Specifies an exponential sequence of buckets that have a width that is
|
||||
// proportional to the value of the lower bound. Each bucket represents a
|
||||
// constant relative uncertainty on a specific value in the bucket.
|
||||
//
|
||||
// There are `num_finite_buckets + 2` (= N) buckets. Bucket `i` has the
|
||||
// following boundaries:
|
||||
//
|
||||
// Upper bound (0 <= i < N-1): scale * (growth_factor ^ i).
|
||||
//
|
||||
// Lower bound (1 <= i < N): scale * (growth_factor ^ (i - 1)).
|
||||
message Exponential {
|
||||
// Must be greater than 0.
|
||||
int32 num_finite_buckets = 1;
|
||||
|
||||
// Must be greater than 1.
|
||||
double growth_factor = 2;
|
||||
|
||||
// Must be greater than 0.
|
||||
double scale = 3;
|
||||
}
|
||||
|
||||
// Specifies a set of buckets with arbitrary widths.
|
||||
//
|
||||
// There are `size(bounds) + 1` (= N) buckets. Bucket `i` has the following
|
||||
// boundaries:
|
||||
//
|
||||
// Upper bound (0 <= i < N-1): bounds[i]
|
||||
// Lower bound (1 <= i < N); bounds[i - 1]
|
||||
//
|
||||
// The `bounds` field must contain at least one element. If `bounds` has
|
||||
// only one element, then there are no finite buckets, and that single
|
||||
// element is the common boundary of the overflow and underflow buckets.
|
||||
message Explicit {
|
||||
// The values must be monotonically increasing.
|
||||
repeated double bounds = 1;
|
||||
}
|
||||
|
||||
// Exactly one of these three fields must be set.
|
||||
oneof options {
|
||||
// The linear bucket.
|
||||
Linear linear_buckets = 1;
|
||||
|
||||
// The exponential buckets.
|
||||
Exponential exponential_buckets = 2;
|
||||
|
||||
// The explicit buckets.
|
||||
Explicit explicit_buckets = 3;
|
||||
}
|
||||
}
|
||||
|
||||
// Exemplars are example points that may be used to annotate aggregated
|
||||
// distribution values. They are metadata that gives information about a
|
||||
// particular value added to a Distribution bucket, such as a trace ID that
|
||||
// was active when a value was added. They may contain further information,
|
||||
// such as a example values and timestamps, origin, etc.
|
||||
message Exemplar {
|
||||
// Value of the exemplar point. This value determines to which bucket the
|
||||
// exemplar belongs.
|
||||
double value = 1;
|
||||
|
||||
// The observation (sampling) time of the above value.
|
||||
google.protobuf.Timestamp timestamp = 2;
|
||||
|
||||
// Contextual information about the example value. Examples are:
|
||||
//
|
||||
// Trace: type.googleapis.com/google.monitoring.v3.SpanContext
|
||||
//
|
||||
// Literal string: type.googleapis.com/google.protobuf.StringValue
|
||||
//
|
||||
// Labels dropped during aggregation:
|
||||
// type.googleapis.com/google.monitoring.v3.DroppedLabels
|
||||
//
|
||||
// There may be only a single attachment of any given message type in a
|
||||
// single exemplar, and this is enforced by the system.
|
||||
repeated google.protobuf.Any attachments = 3;
|
||||
}
|
||||
|
||||
// The number of values in the population. Must be non-negative. This value
|
||||
// must equal the sum of the values in `bucket_counts` if a histogram is
|
||||
// provided.
|
||||
int64 count = 1;
|
||||
|
||||
// The arithmetic mean of the values in the population. If `count` is zero
|
||||
// then this field must be zero.
|
||||
double mean = 2;
|
||||
|
||||
// The sum of squared deviations from the mean of the values in the
|
||||
// population. For values x_i this is:
|
||||
//
|
||||
// Sum[i=1..n]((x_i - mean)^2)
|
||||
//
|
||||
// Knuth, "The Art of Computer Programming", Vol. 2, page 232, 3rd edition
|
||||
// describes Welford's method for accumulating this sum in one pass.
|
||||
//
|
||||
// If `count` is zero then this field must be zero.
|
||||
double sum_of_squared_deviation = 3;
|
||||
|
||||
// If specified, contains the range of the population values. The field
|
||||
// must not be present if the `count` is zero.
|
||||
Range range = 4;
|
||||
|
||||
// Defines the histogram bucket boundaries. If the distribution does not
|
||||
// contain a histogram, then omit this field.
|
||||
BucketOptions bucket_options = 6;
|
||||
|
||||
// The number of values in each bucket of the histogram, as described in
|
||||
// `bucket_options`. If the distribution does not have a histogram, then omit
|
||||
// this field. If there is a histogram, then the sum of the values in
|
||||
// `bucket_counts` must equal the value in the `count` field of the
|
||||
// distribution.
|
||||
//
|
||||
// If present, `bucket_counts` should contain N values, where N is the number
|
||||
// of buckets specified in `bucket_options`. If you supply fewer than N
|
||||
// values, the remaining values are assumed to be 0.
|
||||
//
|
||||
// The order of the values in `bucket_counts` follows the bucket numbering
|
||||
// schemes described for the three bucket types. The first value must be the
|
||||
// count for the underflow bucket (number 0). The next N-2 values are the
|
||||
// counts for the finite buckets (number 1 through N-2). The N'th value in
|
||||
// `bucket_counts` is the count for the overflow bucket (number N-1).
|
||||
repeated int64 bucket_counts = 7;
|
||||
|
||||
// Must be in increasing order of `value` field.
|
||||
repeated Exemplar exemplars = 10;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/distribution.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
|
||||
from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1dgoogle/api/distribution.proto\x12\ngoogle.api\x1a\x19google/protobuf/any.proto\x1a\x1fgoogle/protobuf/timestamp.proto"\xd9\x06\n\x0c\x44istribution\x12\r\n\x05\x63ount\x18\x01 \x01(\x03\x12\x0c\n\x04mean\x18\x02 \x01(\x01\x12 \n\x18sum_of_squared_deviation\x18\x03 \x01(\x01\x12-\n\x05range\x18\x04 \x01(\x0b\x32\x1e.google.api.Distribution.Range\x12>\n\x0e\x62ucket_options\x18\x06 \x01(\x0b\x32&.google.api.Distribution.BucketOptions\x12\x15\n\rbucket_counts\x18\x07 \x03(\x03\x12\x34\n\texemplars\x18\n \x03(\x0b\x32!.google.api.Distribution.Exemplar\x1a!\n\x05Range\x12\x0b\n\x03min\x18\x01 \x01(\x01\x12\x0b\n\x03max\x18\x02 \x01(\x01\x1a\xb5\x03\n\rBucketOptions\x12G\n\x0elinear_buckets\x18\x01 \x01(\x0b\x32-.google.api.Distribution.BucketOptions.LinearH\x00\x12Q\n\x13\x65xponential_buckets\x18\x02 \x01(\x0b\x32\x32.google.api.Distribution.BucketOptions.ExponentialH\x00\x12K\n\x10\x65xplicit_buckets\x18\x03 \x01(\x0b\x32/.google.api.Distribution.BucketOptions.ExplicitH\x00\x1a\x43\n\x06Linear\x12\x1a\n\x12num_finite_buckets\x18\x01 \x01(\x05\x12\r\n\x05width\x18\x02 \x01(\x01\x12\x0e\n\x06offset\x18\x03 \x01(\x01\x1aO\n\x0b\x45xponential\x12\x1a\n\x12num_finite_buckets\x18\x01 \x01(\x05\x12\x15\n\rgrowth_factor\x18\x02 \x01(\x01\x12\r\n\x05scale\x18\x03 \x01(\x01\x1a\x1a\n\x08\x45xplicit\x12\x0e\n\x06\x62ounds\x18\x01 \x03(\x01\x42\t\n\x07options\x1as\n\x08\x45xemplar\x12\r\n\x05value\x18\x01 \x01(\x01\x12-\n\ttimestamp\x18\x02 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12)\n\x0b\x61ttachments\x18\x03 \x03(\x0b\x32\x14.google.protobuf.AnyBq\n\x0e\x63om.google.apiB\x11\x44istributionProtoP\x01ZCgoogle.golang.org/genproto/googleapis/api/distribution;distribution\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.distribution_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\021DistributionProtoP\001ZCgoogle.golang.org/genproto/googleapis/api/distribution;distribution\242\002\004GAPI"
|
||||
_globals["_DISTRIBUTION"]._serialized_start = 106
|
||||
_globals["_DISTRIBUTION"]._serialized_end = 963
|
||||
_globals["_DISTRIBUTION_RANGE"]._serialized_start = 373
|
||||
_globals["_DISTRIBUTION_RANGE"]._serialized_end = 406
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS"]._serialized_start = 409
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS"]._serialized_end = 846
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_LINEAR"]._serialized_start = 659
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_LINEAR"]._serialized_end = 726
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_EXPONENTIAL"]._serialized_start = 728
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_EXPONENTIAL"]._serialized_end = 807
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_EXPLICIT"]._serialized_start = 809
|
||||
_globals["_DISTRIBUTION_BUCKETOPTIONS_EXPLICIT"]._serialized_end = 835
|
||||
_globals["_DISTRIBUTION_EXEMPLAR"]._serialized_start = 848
|
||||
_globals["_DISTRIBUTION_EXEMPLAR"]._serialized_end = 963
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,144 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import any_pb2 as _any_pb2
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf import timestamp_pb2 as _timestamp_pb2
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Distribution(_message.Message):
|
||||
__slots__ = (
|
||||
"count",
|
||||
"mean",
|
||||
"sum_of_squared_deviation",
|
||||
"range",
|
||||
"bucket_options",
|
||||
"bucket_counts",
|
||||
"exemplars",
|
||||
)
|
||||
|
||||
class Range(_message.Message):
|
||||
__slots__ = ("min", "max")
|
||||
MIN_FIELD_NUMBER: _ClassVar[int]
|
||||
MAX_FIELD_NUMBER: _ClassVar[int]
|
||||
min: float
|
||||
max: float
|
||||
def __init__(
|
||||
self, min: _Optional[float] = ..., max: _Optional[float] = ...
|
||||
) -> None: ...
|
||||
|
||||
class BucketOptions(_message.Message):
|
||||
__slots__ = ("linear_buckets", "exponential_buckets", "explicit_buckets")
|
||||
|
||||
class Linear(_message.Message):
|
||||
__slots__ = ("num_finite_buckets", "width", "offset")
|
||||
NUM_FINITE_BUCKETS_FIELD_NUMBER: _ClassVar[int]
|
||||
WIDTH_FIELD_NUMBER: _ClassVar[int]
|
||||
OFFSET_FIELD_NUMBER: _ClassVar[int]
|
||||
num_finite_buckets: int
|
||||
width: float
|
||||
offset: float
|
||||
def __init__(
|
||||
self,
|
||||
num_finite_buckets: _Optional[int] = ...,
|
||||
width: _Optional[float] = ...,
|
||||
offset: _Optional[float] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Exponential(_message.Message):
|
||||
__slots__ = ("num_finite_buckets", "growth_factor", "scale")
|
||||
NUM_FINITE_BUCKETS_FIELD_NUMBER: _ClassVar[int]
|
||||
GROWTH_FACTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
SCALE_FIELD_NUMBER: _ClassVar[int]
|
||||
num_finite_buckets: int
|
||||
growth_factor: float
|
||||
scale: float
|
||||
def __init__(
|
||||
self,
|
||||
num_finite_buckets: _Optional[int] = ...,
|
||||
growth_factor: _Optional[float] = ...,
|
||||
scale: _Optional[float] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Explicit(_message.Message):
|
||||
__slots__ = ("bounds",)
|
||||
BOUNDS_FIELD_NUMBER: _ClassVar[int]
|
||||
bounds: _containers.RepeatedScalarFieldContainer[float]
|
||||
def __init__(self, bounds: _Optional[_Iterable[float]] = ...) -> None: ...
|
||||
LINEAR_BUCKETS_FIELD_NUMBER: _ClassVar[int]
|
||||
EXPONENTIAL_BUCKETS_FIELD_NUMBER: _ClassVar[int]
|
||||
EXPLICIT_BUCKETS_FIELD_NUMBER: _ClassVar[int]
|
||||
linear_buckets: Distribution.BucketOptions.Linear
|
||||
exponential_buckets: Distribution.BucketOptions.Exponential
|
||||
explicit_buckets: Distribution.BucketOptions.Explicit
|
||||
def __init__(
|
||||
self,
|
||||
linear_buckets: _Optional[
|
||||
_Union[Distribution.BucketOptions.Linear, _Mapping]
|
||||
] = ...,
|
||||
exponential_buckets: _Optional[
|
||||
_Union[Distribution.BucketOptions.Exponential, _Mapping]
|
||||
] = ...,
|
||||
explicit_buckets: _Optional[
|
||||
_Union[Distribution.BucketOptions.Explicit, _Mapping]
|
||||
] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Exemplar(_message.Message):
|
||||
__slots__ = ("value", "timestamp", "attachments")
|
||||
VALUE_FIELD_NUMBER: _ClassVar[int]
|
||||
TIMESTAMP_FIELD_NUMBER: _ClassVar[int]
|
||||
ATTACHMENTS_FIELD_NUMBER: _ClassVar[int]
|
||||
value: float
|
||||
timestamp: _timestamp_pb2.Timestamp
|
||||
attachments: _containers.RepeatedCompositeFieldContainer[_any_pb2.Any]
|
||||
def __init__(
|
||||
self,
|
||||
value: _Optional[float] = ...,
|
||||
timestamp: _Optional[_Union[_timestamp_pb2.Timestamp, _Mapping]] = ...,
|
||||
attachments: _Optional[_Iterable[_Union[_any_pb2.Any, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
COUNT_FIELD_NUMBER: _ClassVar[int]
|
||||
MEAN_FIELD_NUMBER: _ClassVar[int]
|
||||
SUM_OF_SQUARED_DEVIATION_FIELD_NUMBER: _ClassVar[int]
|
||||
RANGE_FIELD_NUMBER: _ClassVar[int]
|
||||
BUCKET_OPTIONS_FIELD_NUMBER: _ClassVar[int]
|
||||
BUCKET_COUNTS_FIELD_NUMBER: _ClassVar[int]
|
||||
EXEMPLARS_FIELD_NUMBER: _ClassVar[int]
|
||||
count: int
|
||||
mean: float
|
||||
sum_of_squared_deviation: float
|
||||
range: Distribution.Range
|
||||
bucket_options: Distribution.BucketOptions
|
||||
bucket_counts: _containers.RepeatedScalarFieldContainer[int]
|
||||
exemplars: _containers.RepeatedCompositeFieldContainer[Distribution.Exemplar]
|
||||
def __init__(
|
||||
self,
|
||||
count: _Optional[int] = ...,
|
||||
mean: _Optional[float] = ...,
|
||||
sum_of_squared_deviation: _Optional[float] = ...,
|
||||
range: _Optional[_Union[Distribution.Range, _Mapping]] = ...,
|
||||
bucket_options: _Optional[_Union[Distribution.BucketOptions, _Mapping]] = ...,
|
||||
bucket_counts: _Optional[_Iterable[int]] = ...,
|
||||
exemplars: _Optional[_Iterable[_Union[Distribution.Exemplar, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,168 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "DocumentationProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Documentation` provides the information for describing a service.
|
||||
//
|
||||
// Example:
|
||||
// <pre><code>documentation:
|
||||
// summary: >
|
||||
// The Google Calendar API gives access
|
||||
// to most calendar features.
|
||||
// pages:
|
||||
// - name: Overview
|
||||
// content: (== include google/foo/overview.md ==)
|
||||
// - name: Tutorial
|
||||
// content: (== include google/foo/tutorial.md ==)
|
||||
// subpages:
|
||||
// - name: Java
|
||||
// content: (== include google/foo/tutorial_java.md ==)
|
||||
// rules:
|
||||
// - selector: google.calendar.Calendar.Get
|
||||
// description: >
|
||||
// ...
|
||||
// - selector: google.calendar.Calendar.Put
|
||||
// description: >
|
||||
// ...
|
||||
// </code></pre>
|
||||
// Documentation is provided in markdown syntax. In addition to
|
||||
// standard markdown features, definition lists, tables and fenced
|
||||
// code blocks are supported. Section headers can be provided and are
|
||||
// interpreted relative to the section nesting of the context where
|
||||
// a documentation fragment is embedded.
|
||||
//
|
||||
// Documentation from the IDL is merged with documentation defined
|
||||
// via the config at normalization time, where documentation provided
|
||||
// by config rules overrides IDL provided.
|
||||
//
|
||||
// A number of constructs specific to the API platform are supported
|
||||
// in documentation text.
|
||||
//
|
||||
// In order to reference a proto element, the following
|
||||
// notation can be used:
|
||||
// <pre><code>[fully.qualified.proto.name][]</code></pre>
|
||||
// To override the display text used for the link, this can be used:
|
||||
// <pre><code>[display text][fully.qualified.proto.name]</code></pre>
|
||||
// Text can be excluded from doc using the following notation:
|
||||
// <pre><code>(-- internal comment --)</code></pre>
|
||||
//
|
||||
// A few directives are available in documentation. Note that
|
||||
// directives must appear on a single line to be properly
|
||||
// identified. The `include` directive includes a markdown file from
|
||||
// an external source:
|
||||
// <pre><code>(== include path/to/file ==)</code></pre>
|
||||
// The `resource_for` directive marks a message to be the resource of
|
||||
// a collection in REST view. If it is not specified, tools attempt
|
||||
// to infer the resource from the operations in a collection:
|
||||
// <pre><code>(== resource_for v1.shelves.books ==)</code></pre>
|
||||
// The directive `suppress_warning` does not directly affect documentation
|
||||
// and is documented together with service config validation.
|
||||
message Documentation {
|
||||
// A short description of what the service does. The summary must be plain
|
||||
// text. It becomes the overview of the service displayed in Google Cloud
|
||||
// Console.
|
||||
// NOTE: This field is equivalent to the standard field `description`.
|
||||
string summary = 1;
|
||||
|
||||
// The top level pages for the documentation set.
|
||||
repeated Page pages = 5;
|
||||
|
||||
// A list of documentation rules that apply to individual API elements.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated DocumentationRule rules = 3;
|
||||
|
||||
// The URL to the root of documentation.
|
||||
string documentation_root_url = 4;
|
||||
|
||||
// Specifies the service root url if the default one (the service name
|
||||
// from the yaml file) is not suitable. This can be seen in any fully
|
||||
// specified service urls as well as sections that show a base that other
|
||||
// urls are relative to.
|
||||
string service_root_url = 6;
|
||||
|
||||
// Declares a single overview page. For example:
|
||||
// <pre><code>documentation:
|
||||
// summary: ...
|
||||
// overview: (== include overview.md ==)
|
||||
// </code></pre>
|
||||
// This is a shortcut for the following declaration (using pages style):
|
||||
// <pre><code>documentation:
|
||||
// summary: ...
|
||||
// pages:
|
||||
// - name: Overview
|
||||
// content: (== include overview.md ==)
|
||||
// </code></pre>
|
||||
// Note: you cannot specify both `overview` field and `pages` field.
|
||||
string overview = 2;
|
||||
}
|
||||
|
||||
// A documentation rule provides information about individual API elements.
|
||||
message DocumentationRule {
|
||||
// The selector is a comma-separated list of patterns for any element such as
|
||||
// a method, a field, an enum value. Each pattern is a qualified name of the
|
||||
// element which may end in "*", indicating a wildcard. Wildcards are only
|
||||
// allowed at the end and for a whole component of the qualified name,
|
||||
// i.e. "foo.*" is ok, but not "foo.b*" or "foo.*.bar". A wildcard will match
|
||||
// one or more components. To specify a default for all applicable elements,
|
||||
// the whole pattern "*" is used.
|
||||
string selector = 1;
|
||||
|
||||
// Description of the selected proto element (e.g. a message, a method, a
|
||||
// 'service' definition, or a field). Defaults to leading & trailing comments
|
||||
// taken from the proto source definition of the proto element.
|
||||
string description = 2;
|
||||
|
||||
// Deprecation description of the selected element(s). It can be provided if
|
||||
// an element is marked as `deprecated`.
|
||||
string deprecation_description = 3;
|
||||
}
|
||||
|
||||
// Represents a documentation page. A page can contain subpages to represent
|
||||
// nested documentation set structure.
|
||||
message Page {
|
||||
// The name of the page. It will be used as an identity of the page to
|
||||
// generate URI of the page, text of the link to this page in navigation,
|
||||
// etc. The full page name (start from the root page name to this page
|
||||
// concatenated with `.`) can be used as reference to the page in your
|
||||
// documentation. For example:
|
||||
// <pre><code>pages:
|
||||
// - name: Tutorial
|
||||
// content: (== include tutorial.md ==)
|
||||
// subpages:
|
||||
// - name: Java
|
||||
// content: (== include tutorial_java.md ==)
|
||||
// </code></pre>
|
||||
// You can reference `Java` page using Markdown reference link syntax:
|
||||
// `[Java][Tutorial.Java]`.
|
||||
string name = 1;
|
||||
|
||||
// The Markdown content of the page. You can use ```(== include {path}
|
||||
// ==)``` to include content from a Markdown file. The content can be used
|
||||
// to produce the documentation page such as HTML format page.
|
||||
string content = 2;
|
||||
|
||||
// Subpages of this page. The order of subpages specified here will be
|
||||
// honored in the generated docset.
|
||||
repeated Page subpages = 3;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/documentation.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1egoogle/api/documentation.proto\x12\ngoogle.api"\xbb\x01\n\rDocumentation\x12\x0f\n\x07summary\x18\x01 \x01(\t\x12\x1f\n\x05pages\x18\x05 \x03(\x0b\x32\x10.google.api.Page\x12,\n\x05rules\x18\x03 \x03(\x0b\x32\x1d.google.api.DocumentationRule\x12\x1e\n\x16\x64ocumentation_root_url\x18\x04 \x01(\t\x12\x18\n\x10service_root_url\x18\x06 \x01(\t\x12\x10\n\x08overview\x18\x02 \x01(\t"[\n\x11\x44ocumentationRule\x12\x10\n\x08selector\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x1f\n\x17\x64\x65precation_description\x18\x03 \x01(\t"I\n\x04Page\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x02 \x01(\t\x12"\n\x08subpages\x18\x03 \x03(\x0b\x32\x10.google.api.PageBt\n\x0e\x63om.google.apiB\x12\x44ocumentationProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.documentation_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\022DocumentationProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_DOCUMENTATION"]._serialized_start = 47
|
||||
_globals["_DOCUMENTATION"]._serialized_end = 234
|
||||
_globals["_DOCUMENTATIONRULE"]._serialized_start = 236
|
||||
_globals["_DOCUMENTATIONRULE"]._serialized_end = 327
|
||||
_globals["_PAGE"]._serialized_start = 329
|
||||
_globals["_PAGE"]._serialized_end = 402
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,86 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Documentation(_message.Message):
|
||||
__slots__ = (
|
||||
"summary",
|
||||
"pages",
|
||||
"rules",
|
||||
"documentation_root_url",
|
||||
"service_root_url",
|
||||
"overview",
|
||||
)
|
||||
SUMMARY_FIELD_NUMBER: _ClassVar[int]
|
||||
PAGES_FIELD_NUMBER: _ClassVar[int]
|
||||
RULES_FIELD_NUMBER: _ClassVar[int]
|
||||
DOCUMENTATION_ROOT_URL_FIELD_NUMBER: _ClassVar[int]
|
||||
SERVICE_ROOT_URL_FIELD_NUMBER: _ClassVar[int]
|
||||
OVERVIEW_FIELD_NUMBER: _ClassVar[int]
|
||||
summary: str
|
||||
pages: _containers.RepeatedCompositeFieldContainer[Page]
|
||||
rules: _containers.RepeatedCompositeFieldContainer[DocumentationRule]
|
||||
documentation_root_url: str
|
||||
service_root_url: str
|
||||
overview: str
|
||||
def __init__(
|
||||
self,
|
||||
summary: _Optional[str] = ...,
|
||||
pages: _Optional[_Iterable[_Union[Page, _Mapping]]] = ...,
|
||||
rules: _Optional[_Iterable[_Union[DocumentationRule, _Mapping]]] = ...,
|
||||
documentation_root_url: _Optional[str] = ...,
|
||||
service_root_url: _Optional[str] = ...,
|
||||
overview: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class DocumentationRule(_message.Message):
|
||||
__slots__ = ("selector", "description", "deprecation_description")
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
|
||||
DEPRECATION_DESCRIPTION_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
description: str
|
||||
deprecation_description: str
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
description: _Optional[str] = ...,
|
||||
deprecation_description: _Optional[str] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class Page(_message.Message):
|
||||
__slots__ = ("name", "content", "subpages")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
CONTENT_FIELD_NUMBER: _ClassVar[int]
|
||||
SUBPAGES_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
content: str
|
||||
subpages: _containers.RepeatedCompositeFieldContainer[Page]
|
||||
def __init__(
|
||||
self,
|
||||
name: _Optional[str] = ...,
|
||||
content: _Optional[str] = ...,
|
||||
subpages: _Optional[_Iterable[_Union[Page, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "EndpointProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// `Endpoint` describes a network address of a service that serves a set of
|
||||
// APIs. It is commonly known as a service endpoint. A service may expose
|
||||
// any number of service endpoints, and all service endpoints share the same
|
||||
// service definition, such as quota limits and monitoring metrics.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// type: google.api.Service
|
||||
// name: library-example.googleapis.com
|
||||
// endpoints:
|
||||
// # Declares network address `https://library-example.googleapis.com`
|
||||
// # for service `library-example.googleapis.com`. The `https` scheme
|
||||
// # is implicit for all service endpoints. Other schemes may be
|
||||
// # supported in the future.
|
||||
// - name: library-example.googleapis.com
|
||||
// allow_cors: false
|
||||
// - name: content-staging-library-example.googleapis.com
|
||||
// # Allows HTTP OPTIONS calls to be passed to the API frontend, for it
|
||||
// # to decide whether the subsequent cross-origin request is allowed
|
||||
// # to proceed.
|
||||
// allow_cors: true
|
||||
message Endpoint {
|
||||
// The canonical name of this endpoint.
|
||||
string name = 1;
|
||||
|
||||
// Aliases for this endpoint, these will be served by the same UrlMap as the
|
||||
// parent endpoint, and will be provisioned in the GCP stack for the Regional
|
||||
// Endpoints.
|
||||
repeated string aliases = 2;
|
||||
|
||||
// The specification of an Internet routable address of API frontend that will
|
||||
// handle requests to this [API
|
||||
// Endpoint](https://cloud.google.com/apis/design/glossary). It should be
|
||||
// either a valid IPv4 address or a fully-qualified domain name. For example,
|
||||
// "8.8.8.8" or "myservice.appspot.com".
|
||||
string target = 101;
|
||||
|
||||
// Allowing
|
||||
// [CORS](https://en.wikipedia.org/wiki/Cross-origin_resource_sharing), aka
|
||||
// cross-domain traffic, would allow the backends served from this endpoint to
|
||||
// receive and respond to HTTP OPTIONS requests. The response will be used by
|
||||
// the browser to determine whether the subsequent cross-origin request is
|
||||
// allowed to proceed.
|
||||
bool allow_cors = 5;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/endpoint.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x19google/api/endpoint.proto\x12\ngoogle.api"M\n\x08\x45ndpoint\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x61liases\x18\x02 \x03(\t\x12\x0e\n\x06target\x18\x65 \x01(\t\x12\x12\n\nallow_cors\x18\x05 \x01(\x08\x42o\n\x0e\x63om.google.apiB\rEndpointProtoP\x01ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.endpoint_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\rEndpointProtoP\001ZEgoogle.golang.org/genproto/googleapis/api/serviceconfig;serviceconfig\242\002\004GAPI"
|
||||
_globals["_ENDPOINT"]._serialized_start = 41
|
||||
_globals["_ENDPOINT"]._serialized_end = 118
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,41 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Optional as _Optional
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Endpoint(_message.Message):
|
||||
__slots__ = ("name", "aliases", "target", "allow_cors")
|
||||
NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
ALIASES_FIELD_NUMBER: _ClassVar[int]
|
||||
TARGET_FIELD_NUMBER: _ClassVar[int]
|
||||
ALLOW_CORS_FIELD_NUMBER: _ClassVar[int]
|
||||
name: str
|
||||
aliases: _containers.RepeatedScalarFieldContainer[str]
|
||||
target: str
|
||||
allow_cors: bool
|
||||
def __init__(
|
||||
self,
|
||||
name: _Optional[str] = ...,
|
||||
aliases: _Optional[_Iterable[str]] = ...,
|
||||
target: _Optional[str] = ...,
|
||||
allow_cors: bool = ...,
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,622 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/error_reason;error_reason";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "ErrorReasonProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the supported values for `google.rpc.ErrorInfo.reason` for the
|
||||
// `googleapis.com` error domain. This error domain is reserved for [Service
|
||||
// Infrastructure](https://cloud.google.com/service-infrastructure/docs/overview).
|
||||
// For each error info of this domain, the metadata key "service" refers to the
|
||||
// logical identifier of an API service, such as "pubsub.googleapis.com". The
|
||||
// "consumer" refers to the entity that consumes an API Service. It typically is
|
||||
// a Google project that owns the client application or the server resource,
|
||||
// such as "projects/123". Other metadata keys are specific to each error
|
||||
// reason. For more information, see the definition of the specific error
|
||||
// reason.
|
||||
enum ErrorReason {
|
||||
// Do not use this default value.
|
||||
ERROR_REASON_UNSPECIFIED = 0;
|
||||
|
||||
// The request is calling a disabled service for a consumer.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" contacting
|
||||
// "pubsub.googleapis.com" service which is disabled:
|
||||
//
|
||||
// { "reason": "SERVICE_DISABLED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates the "pubsub.googleapis.com" has been disabled in
|
||||
// "projects/123".
|
||||
SERVICE_DISABLED = 1;
|
||||
|
||||
// The request whose associated billing account is disabled.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to contact
|
||||
// "pubsub.googleapis.com" service because the associated billing account is
|
||||
// disabled:
|
||||
//
|
||||
// { "reason": "BILLING_DISABLED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates the billing account associated has been disabled.
|
||||
BILLING_DISABLED = 2;
|
||||
|
||||
// The request is denied because the provided [API
|
||||
// key](https://cloud.google.com/docs/authentication/api-keys) is invalid. It
|
||||
// may be in a bad format, cannot be found, or has been expired).
|
||||
//
|
||||
// Example of an ErrorInfo when the request is contacting
|
||||
// "storage.googleapis.com" service with an invalid API key:
|
||||
//
|
||||
// { "reason": "API_KEY_INVALID",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// }
|
||||
// }
|
||||
API_KEY_INVALID = 3;
|
||||
|
||||
// The request is denied because it violates [API key API
|
||||
// restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_api_restrictions).
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call the
|
||||
// "storage.googleapis.com" service because this service is restricted in the
|
||||
// API key:
|
||||
//
|
||||
// { "reason": "API_KEY_SERVICE_BLOCKED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
API_KEY_SERVICE_BLOCKED = 4;
|
||||
|
||||
// The request is denied because it violates [API key HTTP
|
||||
// restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_http_restrictions).
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call
|
||||
// "storage.googleapis.com" service because the http referrer of the request
|
||||
// violates API key HTTP restrictions:
|
||||
//
|
||||
// { "reason": "API_KEY_HTTP_REFERRER_BLOCKED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com",
|
||||
// }
|
||||
// }
|
||||
API_KEY_HTTP_REFERRER_BLOCKED = 7;
|
||||
|
||||
// The request is denied because it violates [API key IP address
|
||||
// restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions).
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call
|
||||
// "storage.googleapis.com" service because the caller IP of the request
|
||||
// violates API key IP address restrictions:
|
||||
//
|
||||
// { "reason": "API_KEY_IP_ADDRESS_BLOCKED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com",
|
||||
// }
|
||||
// }
|
||||
API_KEY_IP_ADDRESS_BLOCKED = 8;
|
||||
|
||||
// The request is denied because it violates [API key Android application
|
||||
// restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions).
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call
|
||||
// "storage.googleapis.com" service because the request from the Android apps
|
||||
// violates the API key Android application restrictions:
|
||||
//
|
||||
// { "reason": "API_KEY_ANDROID_APP_BLOCKED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
API_KEY_ANDROID_APP_BLOCKED = 9;
|
||||
|
||||
// The request is denied because it violates [API key iOS application
|
||||
// restrictions](https://cloud.google.com/docs/authentication/api-keys#adding_application_restrictions).
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call
|
||||
// "storage.googleapis.com" service because the request from the iOS apps
|
||||
// violates the API key iOS application restrictions:
|
||||
//
|
||||
// { "reason": "API_KEY_IOS_APP_BLOCKED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
API_KEY_IOS_APP_BLOCKED = 13;
|
||||
|
||||
// The request is denied because there is not enough rate quota for the
|
||||
// consumer.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to contact
|
||||
// "pubsub.googleapis.com" service because consumer's rate quota usage has
|
||||
// reached the maximum value set for the quota limit
|
||||
// "ReadsPerMinutePerProject" on the quota metric
|
||||
// "pubsub.googleapis.com/read_requests":
|
||||
//
|
||||
// { "reason": "RATE_LIMIT_EXCEEDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "pubsub.googleapis.com",
|
||||
// "quota_metric": "pubsub.googleapis.com/read_requests",
|
||||
// "quota_limit": "ReadsPerMinutePerProject"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" checks quota on
|
||||
// the service "dataflow.googleapis.com" and hits the organization quota
|
||||
// limit "DefaultRequestsPerMinutePerOrganization" on the metric
|
||||
// "dataflow.googleapis.com/default_requests".
|
||||
//
|
||||
// { "reason": "RATE_LIMIT_EXCEEDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "dataflow.googleapis.com",
|
||||
// "quota_metric": "dataflow.googleapis.com/default_requests",
|
||||
// "quota_limit": "DefaultRequestsPerMinutePerOrganization"
|
||||
// }
|
||||
// }
|
||||
RATE_LIMIT_EXCEEDED = 5;
|
||||
|
||||
// The request is denied because there is not enough resource quota for the
|
||||
// consumer.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to contact
|
||||
// "compute.googleapis.com" service because consumer's resource quota usage
|
||||
// has reached the maximum value set for the quota limit "VMsPerProject"
|
||||
// on the quota metric "compute.googleapis.com/vms":
|
||||
//
|
||||
// { "reason": "RESOURCE_QUOTA_EXCEEDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "compute.googleapis.com",
|
||||
// "quota_metric": "compute.googleapis.com/vms",
|
||||
// "quota_limit": "VMsPerProject"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" checks resource
|
||||
// quota on the service "dataflow.googleapis.com" and hits the organization
|
||||
// quota limit "jobs-per-organization" on the metric
|
||||
// "dataflow.googleapis.com/job_count".
|
||||
//
|
||||
// { "reason": "RESOURCE_QUOTA_EXCEEDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "dataflow.googleapis.com",
|
||||
// "quota_metric": "dataflow.googleapis.com/job_count",
|
||||
// "quota_limit": "jobs-per-organization"
|
||||
// }
|
||||
// }
|
||||
RESOURCE_QUOTA_EXCEEDED = 6;
|
||||
|
||||
// The request whose associated billing account address is in a tax restricted
|
||||
// location, violates the local tax restrictions when creating resources in
|
||||
// the restricted region.
|
||||
//
|
||||
// Example of an ErrorInfo when creating the Cloud Storage Bucket in the
|
||||
// container "projects/123" under a tax restricted region
|
||||
// "locations/asia-northeast3":
|
||||
//
|
||||
// { "reason": "LOCATION_TAX_POLICY_VIOLATED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com",
|
||||
// "location": "locations/asia-northeast3"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates creating the Cloud Storage Bucket in
|
||||
// "locations/asia-northeast3" violates the location tax restriction.
|
||||
LOCATION_TAX_POLICY_VIOLATED = 10;
|
||||
|
||||
// The request is denied because the caller does not have required permission
|
||||
// on the user project "projects/123" or the user project is invalid. For more
|
||||
// information, check the [userProject System
|
||||
// Parameters](https://cloud.google.com/apis/docs/system-parameters).
|
||||
//
|
||||
// Example of an ErrorInfo when the caller is calling Cloud Storage service
|
||||
// with insufficient permissions on the user project:
|
||||
//
|
||||
// { "reason": "USER_PROJECT_DENIED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
USER_PROJECT_DENIED = 11;
|
||||
|
||||
// The request is denied because the consumer "projects/123" is suspended due
|
||||
// to Terms of Service(Tos) violations. Check [Project suspension
|
||||
// guidelines](https://cloud.google.com/resource-manager/docs/project-suspension-guidelines)
|
||||
// for more information.
|
||||
//
|
||||
// Example of an ErrorInfo when calling Cloud Storage service with the
|
||||
// suspended consumer "projects/123":
|
||||
//
|
||||
// { "reason": "CONSUMER_SUSPENDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
CONSUMER_SUSPENDED = 12;
|
||||
|
||||
// The request is denied because the associated consumer is invalid. It may be
|
||||
// in a bad format, cannot be found, or have been deleted.
|
||||
//
|
||||
// Example of an ErrorInfo when calling Cloud Storage service with the
|
||||
// invalid consumer "projects/123":
|
||||
//
|
||||
// { "reason": "CONSUMER_INVALID",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
CONSUMER_INVALID = 14;
|
||||
|
||||
// The request is denied because it violates [VPC Service
|
||||
// Controls](https://cloud.google.com/vpc-service-controls/docs/overview).
|
||||
// The 'uid' field is a random generated identifier that customer can use it
|
||||
// to search the audit log for a request rejected by VPC Service Controls. For
|
||||
// more information, please refer [VPC Service Controls
|
||||
// Troubleshooting](https://cloud.google.com/vpc-service-controls/docs/troubleshooting#unique-id)
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to call
|
||||
// Cloud Storage service because the request is prohibited by the VPC Service
|
||||
// Controls.
|
||||
//
|
||||
// { "reason": "SECURITY_POLICY_VIOLATED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "uid": "123456789abcde",
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
SECURITY_POLICY_VIOLATED = 15;
|
||||
|
||||
// The request is denied because the provided access token has expired.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is calling Cloud Storage service
|
||||
// with an expired access token:
|
||||
//
|
||||
// { "reason": "ACCESS_TOKEN_EXPIRED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject"
|
||||
// }
|
||||
// }
|
||||
ACCESS_TOKEN_EXPIRED = 16;
|
||||
|
||||
// The request is denied because the provided access token doesn't have at
|
||||
// least one of the acceptable scopes required for the API. Please check
|
||||
// [OAuth 2.0 Scopes for Google
|
||||
// APIs](https://developers.google.com/identity/protocols/oauth2/scopes) for
|
||||
// the list of the OAuth 2.0 scopes that you might need to request to access
|
||||
// the API.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is calling Cloud Storage service
|
||||
// with an access token that is missing required scopes:
|
||||
//
|
||||
// { "reason": "ACCESS_TOKEN_SCOPE_INSUFFICIENT",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject"
|
||||
// }
|
||||
// }
|
||||
ACCESS_TOKEN_SCOPE_INSUFFICIENT = 17;
|
||||
|
||||
// The request is denied because the account associated with the provided
|
||||
// access token is in an invalid state, such as disabled or deleted.
|
||||
// For more information, see https://cloud.google.com/docs/authentication.
|
||||
//
|
||||
// Warning: For privacy reasons, the server may not be able to disclose the
|
||||
// email address for some accounts. The client MUST NOT depend on the
|
||||
// availability of the `email` attribute.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is to the Cloud Storage API with
|
||||
// an access token that is associated with a disabled or deleted [service
|
||||
// account](http://cloud/iam/docs/service-accounts):
|
||||
//
|
||||
// { "reason": "ACCOUNT_STATE_INVALID",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject",
|
||||
// "email": "user@123.iam.gserviceaccount.com"
|
||||
// }
|
||||
// }
|
||||
ACCOUNT_STATE_INVALID = 18;
|
||||
|
||||
// The request is denied because the type of the provided access token is not
|
||||
// supported by the API being called.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is to the Cloud Storage API with
|
||||
// an unsupported token type.
|
||||
//
|
||||
// { "reason": "ACCESS_TOKEN_TYPE_UNSUPPORTED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject"
|
||||
// }
|
||||
// }
|
||||
ACCESS_TOKEN_TYPE_UNSUPPORTED = 19;
|
||||
|
||||
// The request is denied because the request doesn't have any authentication
|
||||
// credentials. For more information regarding the supported authentication
|
||||
// strategies for Google Cloud APIs, see
|
||||
// https://cloud.google.com/docs/authentication.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is to the Cloud Storage API
|
||||
// without any authentication credentials.
|
||||
//
|
||||
// { "reason": "CREDENTIALS_MISSING",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject"
|
||||
// }
|
||||
// }
|
||||
CREDENTIALS_MISSING = 20;
|
||||
|
||||
// The request is denied because the provided project owning the resource
|
||||
// which acts as the [API
|
||||
// consumer](https://cloud.google.com/apis/design/glossary#api_consumer) is
|
||||
// invalid. It may be in a bad format or empty.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is to the Cloud Functions API,
|
||||
// but the offered resource project in the request in a bad format which can't
|
||||
// perform the ListFunctions method.
|
||||
//
|
||||
// { "reason": "RESOURCE_PROJECT_INVALID",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "cloudfunctions.googleapis.com",
|
||||
// "method":
|
||||
// "google.cloud.functions.v1.CloudFunctionsService.ListFunctions"
|
||||
// }
|
||||
// }
|
||||
RESOURCE_PROJECT_INVALID = 21;
|
||||
|
||||
// The request is denied because the provided session cookie is missing,
|
||||
// invalid or failed to decode.
|
||||
//
|
||||
// Example of an ErrorInfo when the request is calling Cloud Storage service
|
||||
// with a SID cookie which can't be decoded.
|
||||
//
|
||||
// { "reason": "SESSION_COOKIE_INVALID",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject",
|
||||
// "cookie": "SID"
|
||||
// }
|
||||
// }
|
||||
SESSION_COOKIE_INVALID = 23;
|
||||
|
||||
// The request is denied because the user is from a Google Workspace customer
|
||||
// that blocks their users from accessing a particular service.
|
||||
//
|
||||
// Example scenario: https://support.google.com/a/answer/9197205?hl=en
|
||||
//
|
||||
// Example of an ErrorInfo when access to Google Cloud Storage service is
|
||||
// blocked by the Google Workspace administrator:
|
||||
//
|
||||
// { "reason": "USER_BLOCKED_BY_ADMIN",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "storage.googleapis.com",
|
||||
// "method": "google.storage.v1.Storage.GetObject",
|
||||
// }
|
||||
// }
|
||||
USER_BLOCKED_BY_ADMIN = 24;
|
||||
|
||||
// The request is denied because the resource service usage is restricted
|
||||
// by administrators according to the organization policy constraint.
|
||||
// For more information see
|
||||
// https://cloud.google.com/resource-manager/docs/organization-policy/restricting-services.
|
||||
//
|
||||
// Example of an ErrorInfo when access to Google Cloud Storage service is
|
||||
// restricted by Resource Usage Restriction policy:
|
||||
//
|
||||
// { "reason": "RESOURCE_USAGE_RESTRICTION_VIOLATED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/project-123",
|
||||
// "service": "storage.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
RESOURCE_USAGE_RESTRICTION_VIOLATED = 25;
|
||||
|
||||
// Unimplemented. Do not use.
|
||||
//
|
||||
// The request is denied because it contains unsupported system parameters in
|
||||
// URL query parameters or HTTP headers. For more information,
|
||||
// see https://cloud.google.com/apis/docs/system-parameters
|
||||
//
|
||||
// Example of an ErrorInfo when access "pubsub.googleapis.com" service with
|
||||
// a request header of "x-goog-user-ip":
|
||||
//
|
||||
// { "reason": "SYSTEM_PARAMETER_UNSUPPORTED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// "parameter": "x-goog-user-ip"
|
||||
// }
|
||||
// }
|
||||
SYSTEM_PARAMETER_UNSUPPORTED = 26;
|
||||
|
||||
// The request is denied because it violates Org Restriction: the requested
|
||||
// resource does not belong to allowed organizations specified in
|
||||
// "X-Goog-Allowed-Resources" header.
|
||||
//
|
||||
// Example of an ErrorInfo when accessing a GCP resource that is restricted by
|
||||
// Org Restriction for "pubsub.googleapis.com" service.
|
||||
//
|
||||
// {
|
||||
// reason: "ORG_RESTRICTION_VIOLATION"
|
||||
// domain: "googleapis.com"
|
||||
// metadata {
|
||||
// "consumer":"projects/123456"
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
ORG_RESTRICTION_VIOLATION = 27;
|
||||
|
||||
// The request is denied because "X-Goog-Allowed-Resources" header is in a bad
|
||||
// format.
|
||||
//
|
||||
// Example of an ErrorInfo when
|
||||
// accessing "pubsub.googleapis.com" service with an invalid
|
||||
// "X-Goog-Allowed-Resources" request header.
|
||||
//
|
||||
// {
|
||||
// reason: "ORG_RESTRICTION_HEADER_INVALID"
|
||||
// domain: "googleapis.com"
|
||||
// metadata {
|
||||
// "consumer":"projects/123456"
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
ORG_RESTRICTION_HEADER_INVALID = 28;
|
||||
|
||||
// Unimplemented. Do not use.
|
||||
//
|
||||
// The request is calling a service that is not visible to the consumer.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" contacting
|
||||
// "pubsub.googleapis.com" service which is not visible to the consumer.
|
||||
//
|
||||
// { "reason": "SERVICE_NOT_VISIBLE",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates the "pubsub.googleapis.com" is not visible to
|
||||
// "projects/123" (or it may not exist).
|
||||
SERVICE_NOT_VISIBLE = 29;
|
||||
|
||||
// The request is related to a project for which GCP access is suspended.
|
||||
//
|
||||
// Example of an ErrorInfo when the consumer "projects/123" fails to contact
|
||||
// "pubsub.googleapis.com" service because GCP access is suspended:
|
||||
//
|
||||
// { "reason": "GCP_SUSPENDED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates the associated GCP account has been suspended.
|
||||
GCP_SUSPENDED = 30;
|
||||
|
||||
// The request violates the location policies when creating resources in
|
||||
// the restricted region.
|
||||
//
|
||||
// Example of an ErrorInfo when creating the Cloud Storage Bucket by
|
||||
// "projects/123" for service storage.googleapis.com:
|
||||
//
|
||||
// { "reason": "LOCATION_POLICY_VIOLATED",
|
||||
// "domain": "googleapis.com",
|
||||
// "metadata": {
|
||||
// "consumer": "projects/123",
|
||||
// "service": "storage.googleapis.com",
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// This response indicates creating the Cloud Storage Bucket in
|
||||
// "locations/asia-northeast3" violates at least one location policy.
|
||||
// The troubleshooting guidance is provided in the Help links.
|
||||
LOCATION_POLICY_VIOLATED = 31;
|
||||
|
||||
// The request is denied because origin request header is missing.
|
||||
//
|
||||
// Example of an ErrorInfo when
|
||||
// accessing "pubsub.googleapis.com" service with an empty "Origin" request
|
||||
// header.
|
||||
//
|
||||
// {
|
||||
// reason: "MISSING_ORIGIN"
|
||||
// domain: "googleapis.com"
|
||||
// metadata {
|
||||
// "consumer":"projects/123456"
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
MISSING_ORIGIN = 33;
|
||||
|
||||
// The request is denied because the request contains more than one credential
|
||||
// type that are individually acceptable, but not together. The customer
|
||||
// should retry their request with only one set of credentials.
|
||||
//
|
||||
// Example of an ErrorInfo when
|
||||
// accessing "pubsub.googleapis.com" service with overloaded credentials.
|
||||
//
|
||||
// {
|
||||
// reason: "OVERLOADED_CREDENTIALS"
|
||||
// domain: "googleapis.com"
|
||||
// metadata {
|
||||
// "consumer":"projects/123456"
|
||||
// "service": "pubsub.googleapis.com"
|
||||
// }
|
||||
// }
|
||||
OVERLOADED_CREDENTIALS = 34;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/error_reason.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1dgoogle/api/error_reason.proto\x12\ngoogle.api*\xba\x07\n\x0b\x45rrorReason\x12\x1c\n\x18\x45RROR_REASON_UNSPECIFIED\x10\x00\x12\x14\n\x10SERVICE_DISABLED\x10\x01\x12\x14\n\x10\x42ILLING_DISABLED\x10\x02\x12\x13\n\x0f\x41PI_KEY_INVALID\x10\x03\x12\x1b\n\x17\x41PI_KEY_SERVICE_BLOCKED\x10\x04\x12!\n\x1d\x41PI_KEY_HTTP_REFERRER_BLOCKED\x10\x07\x12\x1e\n\x1a\x41PI_KEY_IP_ADDRESS_BLOCKED\x10\x08\x12\x1f\n\x1b\x41PI_KEY_ANDROID_APP_BLOCKED\x10\t\x12\x1b\n\x17\x41PI_KEY_IOS_APP_BLOCKED\x10\r\x12\x17\n\x13RATE_LIMIT_EXCEEDED\x10\x05\x12\x1b\n\x17RESOURCE_QUOTA_EXCEEDED\x10\x06\x12 \n\x1cLOCATION_TAX_POLICY_VIOLATED\x10\n\x12\x17\n\x13USER_PROJECT_DENIED\x10\x0b\x12\x16\n\x12\x43ONSUMER_SUSPENDED\x10\x0c\x12\x14\n\x10\x43ONSUMER_INVALID\x10\x0e\x12\x1c\n\x18SECURITY_POLICY_VIOLATED\x10\x0f\x12\x18\n\x14\x41\x43\x43\x45SS_TOKEN_EXPIRED\x10\x10\x12#\n\x1f\x41\x43\x43\x45SS_TOKEN_SCOPE_INSUFFICIENT\x10\x11\x12\x19\n\x15\x41\x43\x43OUNT_STATE_INVALID\x10\x12\x12!\n\x1d\x41\x43\x43\x45SS_TOKEN_TYPE_UNSUPPORTED\x10\x13\x12\x17\n\x13\x43REDENTIALS_MISSING\x10\x14\x12\x1c\n\x18RESOURCE_PROJECT_INVALID\x10\x15\x12\x1a\n\x16SESSION_COOKIE_INVALID\x10\x17\x12\x19\n\x15USER_BLOCKED_BY_ADMIN\x10\x18\x12\'\n#RESOURCE_USAGE_RESTRICTION_VIOLATED\x10\x19\x12 \n\x1cSYSTEM_PARAMETER_UNSUPPORTED\x10\x1a\x12\x1d\n\x19ORG_RESTRICTION_VIOLATION\x10\x1b\x12"\n\x1eORG_RESTRICTION_HEADER_INVALID\x10\x1c\x12\x17\n\x13SERVICE_NOT_VISIBLE\x10\x1d\x12\x11\n\rGCP_SUSPENDED\x10\x1e\x12\x1c\n\x18LOCATION_POLICY_VIOLATED\x10\x1f\x12\x12\n\x0eMISSING_ORIGIN\x10!\x12\x1a\n\x16OVERLOADED_CREDENTIALS\x10"Bp\n\x0e\x63om.google.apiB\x10\x45rrorReasonProtoP\x01ZCgoogle.golang.org/genproto/googleapis/api/error_reason;error_reason\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.error_reason_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\020ErrorReasonProtoP\001ZCgoogle.golang.org/genproto/googleapis/api/error_reason;error_reason\242\002\004GAPI"
|
||||
_globals["_ERRORREASON"]._serialized_start = 46
|
||||
_globals["_ERRORREASON"]._serialized_end = 1000
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,90 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class ErrorReason(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
ERROR_REASON_UNSPECIFIED: _ClassVar[ErrorReason]
|
||||
SERVICE_DISABLED: _ClassVar[ErrorReason]
|
||||
BILLING_DISABLED: _ClassVar[ErrorReason]
|
||||
API_KEY_INVALID: _ClassVar[ErrorReason]
|
||||
API_KEY_SERVICE_BLOCKED: _ClassVar[ErrorReason]
|
||||
API_KEY_HTTP_REFERRER_BLOCKED: _ClassVar[ErrorReason]
|
||||
API_KEY_IP_ADDRESS_BLOCKED: _ClassVar[ErrorReason]
|
||||
API_KEY_ANDROID_APP_BLOCKED: _ClassVar[ErrorReason]
|
||||
API_KEY_IOS_APP_BLOCKED: _ClassVar[ErrorReason]
|
||||
RATE_LIMIT_EXCEEDED: _ClassVar[ErrorReason]
|
||||
RESOURCE_QUOTA_EXCEEDED: _ClassVar[ErrorReason]
|
||||
LOCATION_TAX_POLICY_VIOLATED: _ClassVar[ErrorReason]
|
||||
USER_PROJECT_DENIED: _ClassVar[ErrorReason]
|
||||
CONSUMER_SUSPENDED: _ClassVar[ErrorReason]
|
||||
CONSUMER_INVALID: _ClassVar[ErrorReason]
|
||||
SECURITY_POLICY_VIOLATED: _ClassVar[ErrorReason]
|
||||
ACCESS_TOKEN_EXPIRED: _ClassVar[ErrorReason]
|
||||
ACCESS_TOKEN_SCOPE_INSUFFICIENT: _ClassVar[ErrorReason]
|
||||
ACCOUNT_STATE_INVALID: _ClassVar[ErrorReason]
|
||||
ACCESS_TOKEN_TYPE_UNSUPPORTED: _ClassVar[ErrorReason]
|
||||
CREDENTIALS_MISSING: _ClassVar[ErrorReason]
|
||||
RESOURCE_PROJECT_INVALID: _ClassVar[ErrorReason]
|
||||
SESSION_COOKIE_INVALID: _ClassVar[ErrorReason]
|
||||
USER_BLOCKED_BY_ADMIN: _ClassVar[ErrorReason]
|
||||
RESOURCE_USAGE_RESTRICTION_VIOLATED: _ClassVar[ErrorReason]
|
||||
SYSTEM_PARAMETER_UNSUPPORTED: _ClassVar[ErrorReason]
|
||||
ORG_RESTRICTION_VIOLATION: _ClassVar[ErrorReason]
|
||||
ORG_RESTRICTION_HEADER_INVALID: _ClassVar[ErrorReason]
|
||||
SERVICE_NOT_VISIBLE: _ClassVar[ErrorReason]
|
||||
GCP_SUSPENDED: _ClassVar[ErrorReason]
|
||||
LOCATION_POLICY_VIOLATED: _ClassVar[ErrorReason]
|
||||
MISSING_ORIGIN: _ClassVar[ErrorReason]
|
||||
OVERLOADED_CREDENTIALS: _ClassVar[ErrorReason]
|
||||
|
||||
ERROR_REASON_UNSPECIFIED: ErrorReason
|
||||
SERVICE_DISABLED: ErrorReason
|
||||
BILLING_DISABLED: ErrorReason
|
||||
API_KEY_INVALID: ErrorReason
|
||||
API_KEY_SERVICE_BLOCKED: ErrorReason
|
||||
API_KEY_HTTP_REFERRER_BLOCKED: ErrorReason
|
||||
API_KEY_IP_ADDRESS_BLOCKED: ErrorReason
|
||||
API_KEY_ANDROID_APP_BLOCKED: ErrorReason
|
||||
API_KEY_IOS_APP_BLOCKED: ErrorReason
|
||||
RATE_LIMIT_EXCEEDED: ErrorReason
|
||||
RESOURCE_QUOTA_EXCEEDED: ErrorReason
|
||||
LOCATION_TAX_POLICY_VIOLATED: ErrorReason
|
||||
USER_PROJECT_DENIED: ErrorReason
|
||||
CONSUMER_SUSPENDED: ErrorReason
|
||||
CONSUMER_INVALID: ErrorReason
|
||||
SECURITY_POLICY_VIOLATED: ErrorReason
|
||||
ACCESS_TOKEN_EXPIRED: ErrorReason
|
||||
ACCESS_TOKEN_SCOPE_INSUFFICIENT: ErrorReason
|
||||
ACCOUNT_STATE_INVALID: ErrorReason
|
||||
ACCESS_TOKEN_TYPE_UNSUPPORTED: ErrorReason
|
||||
CREDENTIALS_MISSING: ErrorReason
|
||||
RESOURCE_PROJECT_INVALID: ErrorReason
|
||||
SESSION_COOKIE_INVALID: ErrorReason
|
||||
USER_BLOCKED_BY_ADMIN: ErrorReason
|
||||
RESOURCE_USAGE_RESTRICTION_VIOLATED: ErrorReason
|
||||
SYSTEM_PARAMETER_UNSUPPORTED: ErrorReason
|
||||
ORG_RESTRICTION_VIOLATION: ErrorReason
|
||||
ORG_RESTRICTION_HEADER_INVALID: ErrorReason
|
||||
SERVICE_NOT_VISIBLE: ErrorReason
|
||||
GCP_SUSPENDED: ErrorReason
|
||||
LOCATION_POLICY_VIOLATED: ErrorReason
|
||||
MISSING_ORIGIN: ErrorReason
|
||||
OVERLOADED_CREDENTIALS: ErrorReason
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "FieldBehaviorProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
// A designation of a specific field behavior (required, output only, etc.)
|
||||
// in protobuf messages.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// string name = 1 [(google.api.field_behavior) = REQUIRED];
|
||||
// State state = 1 [(google.api.field_behavior) = OUTPUT_ONLY];
|
||||
// google.protobuf.Duration ttl = 1
|
||||
// [(google.api.field_behavior) = INPUT_ONLY];
|
||||
// google.protobuf.Timestamp expire_time = 1
|
||||
// [(google.api.field_behavior) = OUTPUT_ONLY,
|
||||
// (google.api.field_behavior) = IMMUTABLE];
|
||||
repeated google.api.FieldBehavior field_behavior = 1052 [packed = false];
|
||||
}
|
||||
|
||||
// An indicator of the behavior of a given field (for example, that a field
|
||||
// is required in requests, or given as output but ignored as input).
|
||||
// This **does not** change the behavior in protocol buffers itself; it only
|
||||
// denotes the behavior and may affect how API tooling handles the field.
|
||||
//
|
||||
// Note: This enum **may** receive new values in the future.
|
||||
enum FieldBehavior {
|
||||
// Conventional default for enums. Do not use this.
|
||||
FIELD_BEHAVIOR_UNSPECIFIED = 0;
|
||||
|
||||
// Specifically denotes a field as optional.
|
||||
// While all fields in protocol buffers are optional, this may be specified
|
||||
// for emphasis if appropriate.
|
||||
OPTIONAL = 1;
|
||||
|
||||
// Denotes a field as required.
|
||||
// This indicates that the field **must** be provided as part of the request,
|
||||
// and failure to do so will cause an error (usually `INVALID_ARGUMENT`).
|
||||
REQUIRED = 2;
|
||||
|
||||
// Denotes a field as output only.
|
||||
// This indicates that the field is provided in responses, but including the
|
||||
// field in a request does nothing (the server *must* ignore it and
|
||||
// *must not* throw an error as a result of the field's presence).
|
||||
OUTPUT_ONLY = 3;
|
||||
|
||||
// Denotes a field as input only.
|
||||
// This indicates that the field is provided in requests, and the
|
||||
// corresponding field is not included in output.
|
||||
INPUT_ONLY = 4;
|
||||
|
||||
// Denotes a field as immutable.
|
||||
// This indicates that the field may be set once in a request to create a
|
||||
// resource, but may not be changed thereafter.
|
||||
IMMUTABLE = 5;
|
||||
|
||||
// Denotes that a (repeated) field is an unordered list.
|
||||
// This indicates that the service may provide the elements of the list
|
||||
// in any arbitrary order, rather than the order the user originally
|
||||
// provided. Additionally, the list's order may or may not be stable.
|
||||
UNORDERED_LIST = 6;
|
||||
|
||||
// Denotes that this field returns a non-empty default value if not set.
|
||||
// This indicates that if the user provides the empty value in a request,
|
||||
// a non-empty value will be returned. The user will not be aware of what
|
||||
// non-empty value to expect.
|
||||
NON_EMPTY_DEFAULT = 7;
|
||||
|
||||
// Denotes that the field in a resource (a message annotated with
|
||||
// google.api.resource) is used in the resource name to uniquely identify the
|
||||
// resource. For AIP-compliant APIs, this should only be applied to the
|
||||
// `name` field on the resource.
|
||||
//
|
||||
// This behavior should not be applied to references to other resources within
|
||||
// the message.
|
||||
//
|
||||
// The identifier field of resources often have different field behavior
|
||||
// depending on the request it is embedded in (e.g. for Create methods name
|
||||
// is optional and unused, while for Update methods it is required). Instead
|
||||
// of method-specific annotations, only `IDENTIFIER` is required.
|
||||
IDENTIFIER = 8;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/field_behavior.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b"\n\x1fgoogle/api/field_behavior.proto\x12\ngoogle.api\x1a google/protobuf/descriptor.proto*\xb6\x01\n\rFieldBehavior\x12\x1e\n\x1a\x46IELD_BEHAVIOR_UNSPECIFIED\x10\x00\x12\x0c\n\x08OPTIONAL\x10\x01\x12\x0c\n\x08REQUIRED\x10\x02\x12\x0f\n\x0bOUTPUT_ONLY\x10\x03\x12\x0e\n\nINPUT_ONLY\x10\x04\x12\r\n\tIMMUTABLE\x10\x05\x12\x12\n\x0eUNORDERED_LIST\x10\x06\x12\x15\n\x11NON_EMPTY_DEFAULT\x10\x07\x12\x0e\n\nIDENTIFIER\x10\x08:U\n\x0e\x66ield_behavior\x12\x1d.google.protobuf.FieldOptions\x18\x9c\x08 \x03(\x0e\x32\x19.google.api.FieldBehaviorB\x02\x10\x00\x42p\n\x0e\x63om.google.apiB\x12\x46ieldBehaviorProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3"
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.field_behavior_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\022FieldBehaviorProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
|
||||
_globals["field_behavior"]._options = None
|
||||
_globals["field_behavior"]._serialized_options = b"\020\000"
|
||||
_globals["_FIELDBEHAVIOR"]._serialized_start = 82
|
||||
_globals["_FIELDBEHAVIOR"]._serialized_end = 264
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,45 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2 as _descriptor_pb2
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class FieldBehavior(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
FIELD_BEHAVIOR_UNSPECIFIED: _ClassVar[FieldBehavior]
|
||||
OPTIONAL: _ClassVar[FieldBehavior]
|
||||
REQUIRED: _ClassVar[FieldBehavior]
|
||||
OUTPUT_ONLY: _ClassVar[FieldBehavior]
|
||||
INPUT_ONLY: _ClassVar[FieldBehavior]
|
||||
IMMUTABLE: _ClassVar[FieldBehavior]
|
||||
UNORDERED_LIST: _ClassVar[FieldBehavior]
|
||||
NON_EMPTY_DEFAULT: _ClassVar[FieldBehavior]
|
||||
IDENTIFIER: _ClassVar[FieldBehavior]
|
||||
|
||||
FIELD_BEHAVIOR_UNSPECIFIED: FieldBehavior
|
||||
OPTIONAL: FieldBehavior
|
||||
REQUIRED: FieldBehavior
|
||||
OUTPUT_ONLY: FieldBehavior
|
||||
INPUT_ONLY: FieldBehavior
|
||||
IMMUTABLE: FieldBehavior
|
||||
UNORDERED_LIST: FieldBehavior
|
||||
NON_EMPTY_DEFAULT: FieldBehavior
|
||||
IDENTIFIER: FieldBehavior
|
||||
FIELD_BEHAVIOR_FIELD_NUMBER: _ClassVar[int]
|
||||
field_behavior: _descriptor.FieldDescriptor
|
||||
@@ -0,0 +1,106 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "FieldInfoProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
// Rich semantic descriptor of an API field beyond the basic typing.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// string request_id = 1 [(google.api.field_info).format = UUID4];
|
||||
// string old_ip_address = 2 [(google.api.field_info).format = IPV4];
|
||||
// string new_ip_address = 3 [(google.api.field_info).format = IPV6];
|
||||
// string actual_ip_address = 4 [
|
||||
// (google.api.field_info).format = IPV4_OR_IPV6
|
||||
// ];
|
||||
// google.protobuf.Any generic_field = 5 [
|
||||
// (google.api.field_info).referenced_types = {type_name: "ActualType"},
|
||||
// (google.api.field_info).referenced_types = {type_name: "OtherType"},
|
||||
// ];
|
||||
// google.protobuf.Any generic_user_input = 5 [
|
||||
// (google.api.field_info).referenced_types = {type_name: "*"},
|
||||
// ];
|
||||
google.api.FieldInfo field_info = 291403980;
|
||||
}
|
||||
|
||||
// Rich semantic information of an API field beyond basic typing.
|
||||
message FieldInfo {
|
||||
// The standard format of a field value. The supported formats are all backed
|
||||
// by either an RFC defined by the IETF or a Google-defined AIP.
|
||||
enum Format {
|
||||
// Default, unspecified value.
|
||||
FORMAT_UNSPECIFIED = 0;
|
||||
|
||||
// Universally Unique Identifier, version 4, value as defined by
|
||||
// https://datatracker.ietf.org/doc/html/rfc4122. The value may be
|
||||
// normalized to entirely lowercase letters. For example, the value
|
||||
// `F47AC10B-58CC-0372-8567-0E02B2C3D479` would be normalized to
|
||||
// `f47ac10b-58cc-0372-8567-0e02b2c3d479`.
|
||||
UUID4 = 1;
|
||||
|
||||
// Internet Protocol v4 value as defined by [RFC
|
||||
// 791](https://datatracker.ietf.org/doc/html/rfc791). The value may be
|
||||
// condensed, with leading zeros in each octet stripped. For example,
|
||||
// `001.022.233.040` would be condensed to `1.22.233.40`.
|
||||
IPV4 = 2;
|
||||
|
||||
// Internet Protocol v6 value as defined by [RFC
|
||||
// 2460](https://datatracker.ietf.org/doc/html/rfc2460). The value may be
|
||||
// normalized to entirely lowercase letters with zeros compressed, following
|
||||
// [RFC 5952](https://datatracker.ietf.org/doc/html/rfc5952). For example,
|
||||
// the value `2001:0DB8:0::0` would be normalized to `2001:db8::`.
|
||||
IPV6 = 3;
|
||||
|
||||
// An IP address in either v4 or v6 format as described by the individual
|
||||
// values defined herein. See the comments on the IPV4 and IPV6 types for
|
||||
// allowed normalizations of each.
|
||||
IPV4_OR_IPV6 = 4;
|
||||
}
|
||||
|
||||
// The standard format of a field value. This does not explicitly configure
|
||||
// any API consumer, just documents the API's format for the field it is
|
||||
// applied to.
|
||||
Format format = 1;
|
||||
|
||||
// The type(s) that the annotated, generic field may represent.
|
||||
//
|
||||
// Currently, this must only be used on fields of type `google.protobuf.Any`.
|
||||
// Supporting other generic types may be considered in the future.
|
||||
repeated TypeReference referenced_types = 2;
|
||||
}
|
||||
|
||||
// A reference to a message type, for use in [FieldInfo][google.api.FieldInfo].
|
||||
message TypeReference {
|
||||
// The name of the type that the annotated, generic field may represent.
|
||||
// If the type is in the same protobuf package, the value can be the simple
|
||||
// message name e.g., `"MyMessage"`. Otherwise, the value must be the
|
||||
// fully-qualified message name e.g., `"google.library.v1.Book"`.
|
||||
//
|
||||
// If the type(s) are unknown to the service (e.g. the field accepts generic
|
||||
// user input), use the wildcard `"*"` to denote this behavior.
|
||||
//
|
||||
// See [AIP-202](https://google.aip.dev/202#type-references) for more details.
|
||||
string type_name = 1;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/field_info.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import descriptor_pb2 as google_dot_protobuf_dot_descriptor__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x1bgoogle/api/field_info.proto\x12\ngoogle.api\x1a google/protobuf/descriptor.proto"\xc1\x01\n\tFieldInfo\x12,\n\x06\x66ormat\x18\x01 \x01(\x0e\x32\x1c.google.api.FieldInfo.Format\x12\x33\n\x10referenced_types\x18\x02 \x03(\x0b\x32\x19.google.api.TypeReference"Q\n\x06\x46ormat\x12\x16\n\x12\x46ORMAT_UNSPECIFIED\x10\x00\x12\t\n\x05UUID4\x10\x01\x12\x08\n\x04IPV4\x10\x02\x12\x08\n\x04IPV6\x10\x03\x12\x10\n\x0cIPV4_OR_IPV6\x10\x04""\n\rTypeReference\x12\x11\n\ttype_name\x18\x01 \x01(\t:L\n\nfield_info\x12\x1d.google.protobuf.FieldOptions\x18\xcc\xf1\xf9\x8a\x01 \x01(\x0b\x32\x15.google.api.FieldInfoBl\n\x0e\x63om.google.apiB\x0e\x46ieldInfoProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(
|
||||
DESCRIPTOR, "google.api.field_info_pb2", _globals
|
||||
)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\016FieldInfoProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
|
||||
_globals["_FIELDINFO"]._serialized_start = 78
|
||||
_globals["_FIELDINFO"]._serialized_end = 271
|
||||
_globals["_FIELDINFO_FORMAT"]._serialized_start = 190
|
||||
_globals["_FIELDINFO_FORMAT"]._serialized_end = 271
|
||||
_globals["_TYPEREFERENCE"]._serialized_start = 273
|
||||
_globals["_TYPEREFERENCE"]._serialized_end = 307
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,60 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pb2 as _descriptor_pb2
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
FIELD_INFO_FIELD_NUMBER: _ClassVar[int]
|
||||
field_info: _descriptor.FieldDescriptor
|
||||
|
||||
class FieldInfo(_message.Message):
|
||||
__slots__ = ("format", "referenced_types")
|
||||
|
||||
class Format(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
||||
__slots__ = ()
|
||||
FORMAT_UNSPECIFIED: _ClassVar[FieldInfo.Format]
|
||||
UUID4: _ClassVar[FieldInfo.Format]
|
||||
IPV4: _ClassVar[FieldInfo.Format]
|
||||
IPV6: _ClassVar[FieldInfo.Format]
|
||||
IPV4_OR_IPV6: _ClassVar[FieldInfo.Format]
|
||||
FORMAT_UNSPECIFIED: FieldInfo.Format
|
||||
UUID4: FieldInfo.Format
|
||||
IPV4: FieldInfo.Format
|
||||
IPV6: FieldInfo.Format
|
||||
IPV4_OR_IPV6: FieldInfo.Format
|
||||
FORMAT_FIELD_NUMBER: _ClassVar[int]
|
||||
REFERENCED_TYPES_FIELD_NUMBER: _ClassVar[int]
|
||||
format: FieldInfo.Format
|
||||
referenced_types: _containers.RepeatedCompositeFieldContainer[TypeReference]
|
||||
def __init__(
|
||||
self,
|
||||
format: _Optional[_Union[FieldInfo.Format, str]] = ...,
|
||||
referenced_types: _Optional[_Iterable[_Union[TypeReference, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class TypeReference(_message.Message):
|
||||
__slots__ = ("type_name",)
|
||||
TYPE_NAME_FIELD_NUMBER: _ClassVar[int]
|
||||
type_name: str
|
||||
def __init__(self, type_name: _Optional[str] = ...) -> None: ...
|
||||
370
path/to/venv/lib/python3.12/site-packages/google/api/http.proto
Normal file
370
path/to/venv/lib/python3.12/site-packages/google/api/http.proto
Normal file
@@ -0,0 +1,370 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Defines the HTTP configuration for an API service. It contains a list of
|
||||
// [HttpRule][google.api.HttpRule], each specifying the mapping of an RPC method
|
||||
// to one or more HTTP REST API methods.
|
||||
message Http {
|
||||
// A list of HTTP configuration rules that apply to individual API methods.
|
||||
//
|
||||
// **NOTE:** All service configuration rules follow "last one wins" order.
|
||||
repeated HttpRule rules = 1;
|
||||
|
||||
// When set to true, URL path parameters will be fully URI-decoded except in
|
||||
// cases of single segment matches in reserved expansion, where "%2F" will be
|
||||
// left encoded.
|
||||
//
|
||||
// The default behavior is to not decode RFC 6570 reserved characters in multi
|
||||
// segment matches.
|
||||
bool fully_decode_reserved_expansion = 2;
|
||||
}
|
||||
|
||||
// gRPC Transcoding
|
||||
//
|
||||
// gRPC Transcoding is a feature for mapping between a gRPC method and one or
|
||||
// more HTTP REST endpoints. It allows developers to build a single API service
|
||||
// that supports both gRPC APIs and REST APIs. Many systems, including [Google
|
||||
// APIs](https://github.com/googleapis/googleapis),
|
||||
// [Cloud Endpoints](https://cloud.google.com/endpoints), [gRPC
|
||||
// Gateway](https://github.com/grpc-ecosystem/grpc-gateway),
|
||||
// and [Envoy](https://github.com/envoyproxy/envoy) proxy support this feature
|
||||
// and use it for large scale production services.
|
||||
//
|
||||
// `HttpRule` defines the schema of the gRPC/REST mapping. The mapping specifies
|
||||
// how different portions of the gRPC request message are mapped to the URL
|
||||
// path, URL query parameters, and HTTP request body. It also controls how the
|
||||
// gRPC response message is mapped to the HTTP response body. `HttpRule` is
|
||||
// typically specified as an `google.api.http` annotation on the gRPC method.
|
||||
//
|
||||
// Each mapping specifies a URL path template and an HTTP method. The path
|
||||
// template may refer to one or more fields in the gRPC request message, as long
|
||||
// as each field is a non-repeated field with a primitive (non-message) type.
|
||||
// The path template controls how fields of the request message are mapped to
|
||||
// the URL path.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/{name=messages/*}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string name = 1; // Mapped to URL path.
|
||||
// }
|
||||
// message Message {
|
||||
// string text = 1; // The resource content.
|
||||
// }
|
||||
//
|
||||
// This enables an HTTP REST to gRPC mapping as below:
|
||||
//
|
||||
// - HTTP: `GET /v1/messages/123456`
|
||||
// - gRPC: `GetMessage(name: "messages/123456")`
|
||||
//
|
||||
// Any fields in the request message which are not bound by the path template
|
||||
// automatically become HTTP query parameters if there is no HTTP request body.
|
||||
// For example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get:"/v1/messages/{message_id}"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// message SubMessage {
|
||||
// string subfield = 1;
|
||||
// }
|
||||
// string message_id = 1; // Mapped to URL path.
|
||||
// int64 revision = 2; // Mapped to URL query parameter `revision`.
|
||||
// SubMessage sub = 3; // Mapped to URL query parameter `sub.subfield`.
|
||||
// }
|
||||
//
|
||||
// This enables a HTTP JSON to RPC mapping as below:
|
||||
//
|
||||
// - HTTP: `GET /v1/messages/123456?revision=2&sub.subfield=foo`
|
||||
// - gRPC: `GetMessage(message_id: "123456" revision: 2 sub:
|
||||
// SubMessage(subfield: "foo"))`
|
||||
//
|
||||
// Note that fields which are mapped to URL query parameters must have a
|
||||
// primitive type or a repeated primitive type or a non-repeated message type.
|
||||
// In the case of a repeated type, the parameter can be repeated in the URL
|
||||
// as `...?param=A¶m=B`. In the case of a message type, each field of the
|
||||
// message is mapped to a separate parameter, such as
|
||||
// `...?foo.a=A&foo.b=B&foo.c=C`.
|
||||
//
|
||||
// For HTTP methods that allow a request body, the `body` field
|
||||
// specifies the mapping. Consider a REST update method on the
|
||||
// message resource collection:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(UpdateMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "message"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message UpdateMessageRequest {
|
||||
// string message_id = 1; // mapped to the URL
|
||||
// Message message = 2; // mapped to the body
|
||||
// }
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled, where the
|
||||
// representation of the JSON in the request body is determined by
|
||||
// protos JSON encoding:
|
||||
//
|
||||
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
|
||||
// - gRPC: `UpdateMessage(message_id: "123456" message { text: "Hi!" })`
|
||||
//
|
||||
// The special name `*` can be used in the body mapping to define that
|
||||
// every field not bound by the path template should be mapped to the
|
||||
// request body. This enables the following alternative definition of
|
||||
// the update method:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc UpdateMessage(Message) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// patch: "/v1/messages/{message_id}"
|
||||
// body: "*"
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message Message {
|
||||
// string message_id = 1;
|
||||
// string text = 2;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// The following HTTP JSON to RPC mapping is enabled:
|
||||
//
|
||||
// - HTTP: `PATCH /v1/messages/123456 { "text": "Hi!" }`
|
||||
// - gRPC: `UpdateMessage(message_id: "123456" text: "Hi!")`
|
||||
//
|
||||
// Note that when using `*` in the body mapping, it is not possible to
|
||||
// have HTTP parameters, as all fields not bound by the path end in
|
||||
// the body. This makes this option more rarely used in practice when
|
||||
// defining REST APIs. The common usage of `*` is in custom methods
|
||||
// which don't use the URL at all for transferring data.
|
||||
//
|
||||
// It is possible to define multiple HTTP methods for one RPC by using
|
||||
// the `additional_bindings` option. Example:
|
||||
//
|
||||
// service Messaging {
|
||||
// rpc GetMessage(GetMessageRequest) returns (Message) {
|
||||
// option (google.api.http) = {
|
||||
// get: "/v1/messages/{message_id}"
|
||||
// additional_bindings {
|
||||
// get: "/v1/users/{user_id}/messages/{message_id}"
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
// message GetMessageRequest {
|
||||
// string message_id = 1;
|
||||
// string user_id = 2;
|
||||
// }
|
||||
//
|
||||
// This enables the following two alternative HTTP JSON to RPC mappings:
|
||||
//
|
||||
// - HTTP: `GET /v1/messages/123456`
|
||||
// - gRPC: `GetMessage(message_id: "123456")`
|
||||
//
|
||||
// - HTTP: `GET /v1/users/me/messages/123456`
|
||||
// - gRPC: `GetMessage(user_id: "me" message_id: "123456")`
|
||||
//
|
||||
// Rules for HTTP mapping
|
||||
//
|
||||
// 1. Leaf request fields (recursive expansion nested messages in the request
|
||||
// message) are classified into three categories:
|
||||
// - Fields referred by the path template. They are passed via the URL path.
|
||||
// - Fields referred by the [HttpRule.body][google.api.HttpRule.body]. They
|
||||
// are passed via the HTTP
|
||||
// request body.
|
||||
// - All other fields are passed via the URL query parameters, and the
|
||||
// parameter name is the field path in the request message. A repeated
|
||||
// field can be represented as multiple query parameters under the same
|
||||
// name.
|
||||
// 2. If [HttpRule.body][google.api.HttpRule.body] is "*", there is no URL
|
||||
// query parameter, all fields
|
||||
// are passed via URL path and HTTP request body.
|
||||
// 3. If [HttpRule.body][google.api.HttpRule.body] is omitted, there is no HTTP
|
||||
// request body, all
|
||||
// fields are passed via URL path and URL query parameters.
|
||||
//
|
||||
// Path template syntax
|
||||
//
|
||||
// Template = "/" Segments [ Verb ] ;
|
||||
// Segments = Segment { "/" Segment } ;
|
||||
// Segment = "*" | "**" | LITERAL | Variable ;
|
||||
// Variable = "{" FieldPath [ "=" Segments ] "}" ;
|
||||
// FieldPath = IDENT { "." IDENT } ;
|
||||
// Verb = ":" LITERAL ;
|
||||
//
|
||||
// The syntax `*` matches a single URL path segment. The syntax `**` matches
|
||||
// zero or more URL path segments, which must be the last part of the URL path
|
||||
// except the `Verb`.
|
||||
//
|
||||
// The syntax `Variable` matches part of the URL path as specified by its
|
||||
// template. A variable template must not contain other variables. If a variable
|
||||
// matches a single path segment, its template may be omitted, e.g. `{var}`
|
||||
// is equivalent to `{var=*}`.
|
||||
//
|
||||
// The syntax `LITERAL` matches literal text in the URL path. If the `LITERAL`
|
||||
// contains any reserved character, such characters should be percent-encoded
|
||||
// before the matching.
|
||||
//
|
||||
// If a variable contains exactly one path segment, such as `"{var}"` or
|
||||
// `"{var=*}"`, when such a variable is expanded into a URL path on the client
|
||||
// side, all characters except `[-_.~0-9a-zA-Z]` are percent-encoded. The
|
||||
// server side does the reverse decoding. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{var}`.
|
||||
//
|
||||
// If a variable contains multiple path segments, such as `"{var=foo/*}"`
|
||||
// or `"{var=**}"`, when such a variable is expanded into a URL path on the
|
||||
// client side, all characters except `[-_.~/0-9a-zA-Z]` are percent-encoded.
|
||||
// The server side does the reverse decoding, except "%2F" and "%2f" are left
|
||||
// unchanged. Such variables show up in the
|
||||
// [Discovery
|
||||
// Document](https://developers.google.com/discovery/v1/reference/apis) as
|
||||
// `{+var}`.
|
||||
//
|
||||
// Using gRPC API Service Configuration
|
||||
//
|
||||
// gRPC API Service Configuration (service config) is a configuration language
|
||||
// for configuring a gRPC service to become a user-facing product. The
|
||||
// service config is simply the YAML representation of the `google.api.Service`
|
||||
// proto message.
|
||||
//
|
||||
// As an alternative to annotating your proto file, you can configure gRPC
|
||||
// transcoding in your service config YAML files. You do this by specifying a
|
||||
// `HttpRule` that maps the gRPC method to a REST endpoint, achieving the same
|
||||
// effect as the proto annotation. This can be particularly useful if you
|
||||
// have a proto that is reused in multiple services. Note that any transcoding
|
||||
// specified in the service config will override any matching transcoding
|
||||
// configuration in the proto.
|
||||
//
|
||||
// The following example selects a gRPC method and applies an `HttpRule` to it:
|
||||
//
|
||||
// http:
|
||||
// rules:
|
||||
// - selector: example.v1.Messaging.GetMessage
|
||||
// get: /v1/messages/{message_id}/{sub.subfield}
|
||||
//
|
||||
// Special notes
|
||||
//
|
||||
// When gRPC Transcoding is used to map a gRPC to JSON REST endpoints, the
|
||||
// proto to JSON conversion must follow the [proto3
|
||||
// specification](https://developers.google.com/protocol-buffers/docs/proto3#json).
|
||||
//
|
||||
// While the single segment variable follows the semantics of
|
||||
// [RFC 6570](https://tools.ietf.org/html/rfc6570) Section 3.2.2 Simple String
|
||||
// Expansion, the multi segment variable **does not** follow RFC 6570 Section
|
||||
// 3.2.3 Reserved Expansion. The reason is that the Reserved Expansion
|
||||
// does not expand special characters like `?` and `#`, which would lead
|
||||
// to invalid URLs. As the result, gRPC Transcoding uses a custom encoding
|
||||
// for multi segment variables.
|
||||
//
|
||||
// The path variables **must not** refer to any repeated or mapped field,
|
||||
// because client libraries are not capable of handling such variable expansion.
|
||||
//
|
||||
// The path variables **must not** capture the leading "/" character. The reason
|
||||
// is that the most common use case "{var}" does not capture the leading "/"
|
||||
// character. For consistency, all path variables must share the same behavior.
|
||||
//
|
||||
// Repeated message fields must not be mapped to URL query parameters, because
|
||||
// no client library can support such complicated mapping.
|
||||
//
|
||||
// If an API needs to use a JSON array for request or response body, it can map
|
||||
// the request or response body to a repeated field. However, some gRPC
|
||||
// Transcoding implementations may not support this feature.
|
||||
message HttpRule {
|
||||
// Selects a method to which this rule applies.
|
||||
//
|
||||
// Refer to [selector][google.api.DocumentationRule.selector] for syntax
|
||||
// details.
|
||||
string selector = 1;
|
||||
|
||||
// Determines the URL pattern is matched by this rules. This pattern can be
|
||||
// used with any of the {get|put|post|delete|patch} methods. A custom method
|
||||
// can be defined using the 'custom' field.
|
||||
oneof pattern {
|
||||
// Maps to HTTP GET. Used for listing and getting information about
|
||||
// resources.
|
||||
string get = 2;
|
||||
|
||||
// Maps to HTTP PUT. Used for replacing a resource.
|
||||
string put = 3;
|
||||
|
||||
// Maps to HTTP POST. Used for creating a resource or performing an action.
|
||||
string post = 4;
|
||||
|
||||
// Maps to HTTP DELETE. Used for deleting a resource.
|
||||
string delete = 5;
|
||||
|
||||
// Maps to HTTP PATCH. Used for updating a resource.
|
||||
string patch = 6;
|
||||
|
||||
// The custom pattern is used for specifying an HTTP method that is not
|
||||
// included in the `pattern` field, such as HEAD, or "*" to leave the
|
||||
// HTTP method unspecified for this rule. The wild-card rule is useful
|
||||
// for services that provide content to Web (HTML) clients.
|
||||
CustomHttpPattern custom = 8;
|
||||
}
|
||||
|
||||
// The name of the request field whose value is mapped to the HTTP request
|
||||
// body, or `*` for mapping all request fields not captured by the path
|
||||
// pattern to the HTTP body, or omitted for not having any HTTP request body.
|
||||
//
|
||||
// NOTE: the referred field must be present at the top-level of the request
|
||||
// message type.
|
||||
string body = 7;
|
||||
|
||||
// Optional. The name of the response field whose value is mapped to the HTTP
|
||||
// response body. When omitted, the entire response message will be used
|
||||
// as the HTTP response body.
|
||||
//
|
||||
// NOTE: The referred field must be present at the top-level of the response
|
||||
// message type.
|
||||
string response_body = 12;
|
||||
|
||||
// Additional HTTP bindings for the selector. Nested bindings must
|
||||
// not contain an `additional_bindings` field themselves (that is,
|
||||
// the nesting may only be one level deep).
|
||||
repeated HttpRule additional_bindings = 11;
|
||||
}
|
||||
|
||||
// A custom pattern is used for defining custom HTTP verb.
|
||||
message CustomHttpPattern {
|
||||
// The name of this custom HTTP verb.
|
||||
string kind = 1;
|
||||
|
||||
// The path matched by this custom verb.
|
||||
string path = 2;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/http.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x15google/api/http.proto\x12\ngoogle.api"T\n\x04Http\x12#\n\x05rules\x18\x01 \x03(\x0b\x32\x14.google.api.HttpRule\x12\'\n\x1f\x66ully_decode_reserved_expansion\x18\x02 \x01(\x08"\x81\x02\n\x08HttpRule\x12\x10\n\x08selector\x18\x01 \x01(\t\x12\r\n\x03get\x18\x02 \x01(\tH\x00\x12\r\n\x03put\x18\x03 \x01(\tH\x00\x12\x0e\n\x04post\x18\x04 \x01(\tH\x00\x12\x10\n\x06\x64\x65lete\x18\x05 \x01(\tH\x00\x12\x0f\n\x05patch\x18\x06 \x01(\tH\x00\x12/\n\x06\x63ustom\x18\x08 \x01(\x0b\x32\x1d.google.api.CustomHttpPatternH\x00\x12\x0c\n\x04\x62ody\x18\x07 \x01(\t\x12\x15\n\rresponse_body\x18\x0c \x01(\t\x12\x31\n\x13\x61\x64\x64itional_bindings\x18\x0b \x03(\x0b\x32\x14.google.api.HttpRuleB\t\n\x07pattern"/\n\x11\x43ustomHttpPattern\x12\x0c\n\x04kind\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\tBg\n\x0e\x63om.google.apiB\tHttpProtoP\x01ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.http_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\tHttpProtoP\001ZAgoogle.golang.org/genproto/googleapis/api/annotations;annotations\242\002\004GAPI"
|
||||
_globals["_HTTP"]._serialized_start = 37
|
||||
_globals["_HTTP"]._serialized_end = 121
|
||||
_globals["_HTTPRULE"]._serialized_start = 124
|
||||
_globals["_HTTPRULE"]._serialized_end = 381
|
||||
_globals["_CUSTOMHTTPPATTERN"]._serialized_start = 383
|
||||
_globals["_CUSTOMHTTPPATTERN"]._serialized_end = 430
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
@@ -0,0 +1,94 @@
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
from typing import ClassVar as _ClassVar
|
||||
from typing import Iterable as _Iterable
|
||||
from typing import Mapping as _Mapping
|
||||
from typing import Optional as _Optional
|
||||
from typing import Union as _Union
|
||||
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import message as _message
|
||||
from google.protobuf.internal import containers as _containers
|
||||
|
||||
DESCRIPTOR: _descriptor.FileDescriptor
|
||||
|
||||
class Http(_message.Message):
|
||||
__slots__ = ("rules", "fully_decode_reserved_expansion")
|
||||
RULES_FIELD_NUMBER: _ClassVar[int]
|
||||
FULLY_DECODE_RESERVED_EXPANSION_FIELD_NUMBER: _ClassVar[int]
|
||||
rules: _containers.RepeatedCompositeFieldContainer[HttpRule]
|
||||
fully_decode_reserved_expansion: bool
|
||||
def __init__(
|
||||
self,
|
||||
rules: _Optional[_Iterable[_Union[HttpRule, _Mapping]]] = ...,
|
||||
fully_decode_reserved_expansion: bool = ...,
|
||||
) -> None: ...
|
||||
|
||||
class HttpRule(_message.Message):
|
||||
__slots__ = (
|
||||
"selector",
|
||||
"get",
|
||||
"put",
|
||||
"post",
|
||||
"delete",
|
||||
"patch",
|
||||
"custom",
|
||||
"body",
|
||||
"response_body",
|
||||
"additional_bindings",
|
||||
)
|
||||
SELECTOR_FIELD_NUMBER: _ClassVar[int]
|
||||
GET_FIELD_NUMBER: _ClassVar[int]
|
||||
PUT_FIELD_NUMBER: _ClassVar[int]
|
||||
POST_FIELD_NUMBER: _ClassVar[int]
|
||||
DELETE_FIELD_NUMBER: _ClassVar[int]
|
||||
PATCH_FIELD_NUMBER: _ClassVar[int]
|
||||
CUSTOM_FIELD_NUMBER: _ClassVar[int]
|
||||
BODY_FIELD_NUMBER: _ClassVar[int]
|
||||
RESPONSE_BODY_FIELD_NUMBER: _ClassVar[int]
|
||||
ADDITIONAL_BINDINGS_FIELD_NUMBER: _ClassVar[int]
|
||||
selector: str
|
||||
get: str
|
||||
put: str
|
||||
post: str
|
||||
delete: str
|
||||
patch: str
|
||||
custom: CustomHttpPattern
|
||||
body: str
|
||||
response_body: str
|
||||
additional_bindings: _containers.RepeatedCompositeFieldContainer[HttpRule]
|
||||
def __init__(
|
||||
self,
|
||||
selector: _Optional[str] = ...,
|
||||
get: _Optional[str] = ...,
|
||||
put: _Optional[str] = ...,
|
||||
post: _Optional[str] = ...,
|
||||
delete: _Optional[str] = ...,
|
||||
patch: _Optional[str] = ...,
|
||||
custom: _Optional[_Union[CustomHttpPattern, _Mapping]] = ...,
|
||||
body: _Optional[str] = ...,
|
||||
response_body: _Optional[str] = ...,
|
||||
additional_bindings: _Optional[_Iterable[_Union[HttpRule, _Mapping]]] = ...,
|
||||
) -> None: ...
|
||||
|
||||
class CustomHttpPattern(_message.Message):
|
||||
__slots__ = ("kind", "path")
|
||||
KIND_FIELD_NUMBER: _ClassVar[int]
|
||||
PATH_FIELD_NUMBER: _ClassVar[int]
|
||||
kind: str
|
||||
path: str
|
||||
def __init__(
|
||||
self, kind: _Optional[str] = ..., path: _Optional[str] = ...
|
||||
) -> None: ...
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2025 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.api;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
|
||||
option go_package = "google.golang.org/genproto/googleapis/api/httpbody;httpbody";
|
||||
option java_multiple_files = true;
|
||||
option java_outer_classname = "HttpBodyProto";
|
||||
option java_package = "com.google.api";
|
||||
option objc_class_prefix = "GAPI";
|
||||
|
||||
// Message that represents an arbitrary HTTP body. It should only be used for
|
||||
// payload formats that can't be represented as JSON, such as raw binary or
|
||||
// an HTML page.
|
||||
//
|
||||
//
|
||||
// This message can be used both in streaming and non-streaming API methods in
|
||||
// the request as well as the response.
|
||||
//
|
||||
// It can be used as a top-level request field, which is convenient if one
|
||||
// wants to extract parameters from either the URL or HTTP template into the
|
||||
// request fields and also want access to the raw HTTP body.
|
||||
//
|
||||
// Example:
|
||||
//
|
||||
// message GetResourceRequest {
|
||||
// // A unique request id.
|
||||
// string request_id = 1;
|
||||
//
|
||||
// // The raw HTTP body is bound to this field.
|
||||
// google.api.HttpBody http_body = 2;
|
||||
//
|
||||
// }
|
||||
//
|
||||
// service ResourceService {
|
||||
// rpc GetResource(GetResourceRequest)
|
||||
// returns (google.api.HttpBody);
|
||||
// rpc UpdateResource(google.api.HttpBody)
|
||||
// returns (google.protobuf.Empty);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// Example with streaming methods:
|
||||
//
|
||||
// service CaldavService {
|
||||
// rpc GetCalendar(stream google.api.HttpBody)
|
||||
// returns (stream google.api.HttpBody);
|
||||
// rpc UpdateCalendar(stream google.api.HttpBody)
|
||||
// returns (stream google.api.HttpBody);
|
||||
//
|
||||
// }
|
||||
//
|
||||
// Use of this type only changes how the request and response bodies are
|
||||
// handled, all other features will continue to work unchanged.
|
||||
message HttpBody {
|
||||
// The HTTP Content-Type header value specifying the content type of the body.
|
||||
string content_type = 1;
|
||||
|
||||
// The HTTP request/response body as raw binary.
|
||||
bytes data = 2;
|
||||
|
||||
// Application specific response metadata. Must be set in the first response
|
||||
// for streaming APIs.
|
||||
repeated google.protobuf.Any extensions = 3;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2025 Google LLC
|
||||
#
|
||||
# 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.
|
||||
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# source: google/api/httpbody.proto
|
||||
# Protobuf Python Version: 4.25.3
|
||||
"""Generated protocol buffer code."""
|
||||
from google.protobuf import descriptor as _descriptor
|
||||
from google.protobuf import descriptor_pool as _descriptor_pool
|
||||
from google.protobuf import symbol_database as _symbol_database
|
||||
from google.protobuf.internal import builder as _builder
|
||||
|
||||
# @@protoc_insertion_point(imports)
|
||||
|
||||
_sym_db = _symbol_database.Default()
|
||||
|
||||
|
||||
from google.protobuf import any_pb2 as google_dot_protobuf_dot_any__pb2
|
||||
|
||||
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(
|
||||
b'\n\x19google/api/httpbody.proto\x12\ngoogle.api\x1a\x19google/protobuf/any.proto"X\n\x08HttpBody\x12\x14\n\x0c\x63ontent_type\x18\x01 \x01(\t\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12(\n\nextensions\x18\x03 \x03(\x0b\x32\x14.google.protobuf.AnyBe\n\x0e\x63om.google.apiB\rHttpBodyProtoP\x01Z;google.golang.org/genproto/googleapis/api/httpbody;httpbody\xa2\x02\x04GAPIb\x06proto3'
|
||||
)
|
||||
|
||||
_globals = globals()
|
||||
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
||||
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, "google.api.httpbody_pb2", _globals)
|
||||
if _descriptor._USE_C_DESCRIPTORS == False:
|
||||
_globals["DESCRIPTOR"]._options = None
|
||||
_globals[
|
||||
"DESCRIPTOR"
|
||||
]._serialized_options = b"\n\016com.google.apiB\rHttpBodyProtoP\001Z;google.golang.org/genproto/googleapis/api/httpbody;httpbody\242\002\004GAPI"
|
||||
_globals["_HTTPBODY"]._serialized_start = 68
|
||||
_globals["_HTTPBODY"]._serialized_end = 156
|
||||
# @@protoc_insertion_point(module_scope)
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user