aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-08-22 10:43:37 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-08-22 10:52:34 +0300
commit1fbd27b4e37aecbce5bc29b1084ebc08d49c44ab (patch)
treedc2e6502cd69163a7309a5a2b5ee7bc0f7b1d736
parent09b7cd61fa6d98c03d6612f2130641e209f61a06 (diff)
downloadydb-1fbd27b4e37aecbce5bc29b1084ebc08d49c44ab.tar.gz
Intermediate changes
-rw-r--r--contrib/python/google-auth/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/google-auth/py3/google/auth/_credentials_base.py75
-rw-r--r--contrib/python/google-auth/py3/google/auth/_exponential_backoff.py10
-rw-r--r--contrib/python/google-auth/py3/google/auth/aio/__init__.py25
-rw-r--r--contrib/python/google-auth/py3/google/auth/aio/credentials.py143
-rw-r--r--contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py21
-rw-r--r--contrib/python/google-auth/py3/google/auth/credentials.py12
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/_requests_base.py52
-rw-r--r--contrib/python/google-auth/py3/google/auth/transport/requests.py5
-rw-r--r--contrib/python/google-auth/py3/google/auth/version.py2
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/_client.py22
-rw-r--r--contrib/python/google-auth/py3/google/oauth2/_client_async.py20
-rw-r--r--contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py15
-rw-r--r--contrib/python/google-auth/py3/tests/oauth2/test__client.py10
-rw-r--r--contrib/python/google-auth/py3/tests/test__exponential_backoff.py35
-rw-r--r--contrib/python/google-auth/py3/tests/test_credentials_async.py136
-rw-r--r--contrib/python/google-auth/py3/ya.make6
-rw-r--r--contrib/python/hypothesis/py3/.dist-info/METADATA2
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/cathetus.py2
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py6
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py18
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/optimiser.py39
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py40
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py6
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/internal/floats.py66
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py73
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/strategies/_internal/numbers.py16
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py45
-rw-r--r--contrib/python/hypothesis/py3/hypothesis/version.py2
-rw-r--r--contrib/python/hypothesis/py3/ya.make2
30 files changed, 750 insertions, 158 deletions
diff --git a/contrib/python/google-auth/py3/.dist-info/METADATA b/contrib/python/google-auth/py3/.dist-info/METADATA
index 1814862af6..cdbc683396 100644
--- a/contrib/python/google-auth/py3/.dist-info/METADATA
+++ b/contrib/python/google-auth/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: google-auth
-Version: 2.32.0
+Version: 2.33.0
Summary: Google Authentication Library
Home-page: https://github.com/googleapis/google-auth-library-python
Author: Google Cloud Platform
diff --git a/contrib/python/google-auth/py3/google/auth/_credentials_base.py b/contrib/python/google-auth/py3/google/auth/_credentials_base.py
new file mode 100644
index 0000000000..64d5ce34b9
--- /dev/null
+++ b/contrib/python/google-auth/py3/google/auth/_credentials_base.py
@@ -0,0 +1,75 @@
+# Copyright 2024 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.
+
+
+"""Interface for base credentials."""
+
+import abc
+
+from google.auth import _helpers
+
+
+class _BaseCredentials(metaclass=abc.ABCMeta):
+ """Base class for all credentials.
+
+ All credentials have a :attr:`token` that is used for authentication and
+ may also optionally set an :attr:`expiry` to indicate when the token will
+ no longer be valid.
+
+ Most credentials will be :attr:`invalid` until :meth:`refresh` is called.
+ Credentials can do this automatically before the first HTTP request in
+ :meth:`before_request`.
+
+ Although the token and expiration will change as the credentials are
+ :meth:`refreshed <refresh>` and used, credentials should be considered
+ immutable. Various credentials will accept configuration such as private
+ keys, scopes, and other options. These options are not changeable after
+ construction. Some classes will provide mechanisms to copy the credentials
+ with modifications such as :meth:`ScopedCredentials.with_scopes`.
+
+ Attributes:
+ token (Optional[str]): The bearer token that can be used in HTTP headers to make
+ authenticated requests.
+ """
+
+ def __init__(self):
+ self.token = None
+
+ @abc.abstractmethod
+ def refresh(self, request):
+ """Refreshes the access token.
+
+ Args:
+ request (google.auth.transport.Request): The object used to make
+ HTTP requests.
+
+ Raises:
+ google.auth.exceptions.RefreshError: If the credentials could
+ not be refreshed.
+ """
+ # pylint: disable=missing-raises-doc
+ # (pylint doesn't recognize that this is abstract)
+ raise NotImplementedError("Refresh must be implemented")
+
+ def _apply(self, headers, token=None):
+ """Apply the token to the authentication header.
+
+ Args:
+ headers (Mapping): The HTTP request headers.
+ token (Optional[str]): If specified, overrides the current access
+ token.
+ """
+ headers["authorization"] = "Bearer {}".format(
+ _helpers.from_bytes(token or self.token)
+ )
diff --git a/contrib/python/google-auth/py3/google/auth/_exponential_backoff.py b/contrib/python/google-auth/py3/google/auth/_exponential_backoff.py
index 0dd621a949..04f9f97641 100644
--- a/contrib/python/google-auth/py3/google/auth/_exponential_backoff.py
+++ b/contrib/python/google-auth/py3/google/auth/_exponential_backoff.py
@@ -15,6 +15,8 @@
import random
import time
+from google.auth import exceptions
+
# The default amount of retry attempts
_DEFAULT_RETRY_TOTAL_ATTEMPTS = 3
@@ -68,6 +70,11 @@ class ExponentialBackoff:
randomization_factor=_DEFAULT_RANDOMIZATION_FACTOR,
multiplier=_DEFAULT_MULTIPLIER,
):
+ if total_attempts < 1:
+ raise exceptions.InvalidValue(
+ f"total_attempts must be greater than or equal to 1 but was {total_attempts}"
+ )
+
self._total_attempts = total_attempts
self._initial_wait_seconds = initial_wait_seconds
@@ -87,6 +94,9 @@ class ExponentialBackoff:
raise StopIteration
self._backoff_count += 1
+ if self._backoff_count <= 1:
+ return self._backoff_count
+
jitter_variance = self._current_wait_in_seconds * self._randomization_factor
jitter = random.uniform(
self._current_wait_in_seconds - jitter_variance,
diff --git a/contrib/python/google-auth/py3/google/auth/aio/__init__.py b/contrib/python/google-auth/py3/google/auth/aio/__init__.py
new file mode 100644
index 0000000000..331708cba6
--- /dev/null
+++ b/contrib/python/google-auth/py3/google/auth/aio/__init__.py
@@ -0,0 +1,25 @@
+# Copyright 2024 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.
+
+"""Google Auth AIO Library for Python."""
+
+import logging
+
+from google.auth import version as google_auth_version
+
+
+__version__ = google_auth_version.__version__
+
+# Set default logging handler to avoid "No handler found" warnings.
+logging.getLogger(__name__).addHandler(logging.NullHandler())
diff --git a/contrib/python/google-auth/py3/google/auth/aio/credentials.py b/contrib/python/google-auth/py3/google/auth/aio/credentials.py
new file mode 100644
index 0000000000..3bc6a5a676
--- /dev/null
+++ b/contrib/python/google-auth/py3/google/auth/aio/credentials.py
@@ -0,0 +1,143 @@
+# Copyright 2024 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.
+
+
+"""Interfaces for asynchronous credentials."""
+
+
+from google.auth import _helpers
+from google.auth import exceptions
+from google.auth._credentials_base import _BaseCredentials
+
+
+class Credentials(_BaseCredentials):
+ """Base class for all asynchronous credentials.
+
+ All credentials have a :attr:`token` that is used for authentication and
+ may also optionally set an :attr:`expiry` to indicate when the token will
+ no longer be valid.
+
+ Most credentials will be :attr:`invalid` until :meth:`refresh` is called.
+ Credentials can do this automatically before the first HTTP request in
+ :meth:`before_request`.
+
+ Although the token and expiration will change as the credentials are
+ :meth:`refreshed <refresh>` and used, credentials should be considered
+ immutable. Various credentials will accept configuration such as private
+ keys, scopes, and other options. These options are not changeable after
+ construction. Some classes will provide mechanisms to copy the credentials
+ with modifications such as :meth:`ScopedCredentials.with_scopes`.
+ """
+
+ def __init__(self):
+ super(Credentials, self).__init__()
+
+ async def apply(self, headers, token=None):
+ """Apply the token to the authentication header.
+
+ Args:
+ headers (Mapping): The HTTP request headers.
+ token (Optional[str]): If specified, overrides the current access
+ token.
+ """
+ self._apply(headers, token=token)
+
+ async def refresh(self, request):
+ """Refreshes the access token.
+
+ Args:
+ request (google.auth.aio.transport.Request): The object used to make
+ HTTP requests.
+
+ Raises:
+ google.auth.exceptions.RefreshError: If the credentials could
+ not be refreshed.
+ """
+ raise NotImplementedError("Refresh must be implemented")
+
+ async def before_request(self, request, method, url, headers):
+ """Performs credential-specific before request logic.
+
+ Refreshes the credentials if necessary, then calls :meth:`apply` to
+ apply the token to the authentication header.
+
+ Args:
+ request (google.auth.aio.transport.Request): The object used to make
+ HTTP requests.
+ method (str): The request's HTTP method or the RPC method being
+ invoked.
+ url (str): The request's URI or the RPC service's URI.
+ headers (Mapping): The request's headers.
+ """
+ await self.apply(headers)
+
+
+class StaticCredentials(Credentials):
+ """Asynchronous Credentials representing an immutable access token.
+
+ The credentials are considered immutable except the tokens which can be
+ configured in the constructor ::
+
+ credentials = StaticCredentials(token="token123")
+
+ StaticCredentials does not support :meth `refresh` and assumes that the configured
+ token is valid and not expired. StaticCredentials will never attempt to
+ refresh the token.
+ """
+
+ def __init__(self, token):
+ """
+ Args:
+ token (str): The access token.
+ """
+ super(StaticCredentials, self).__init__()
+ self.token = token
+
+ @_helpers.copy_docstring(Credentials)
+ async def refresh(self, request):
+ raise exceptions.InvalidOperation("Static credentials cannot be refreshed.")
+
+ # Note: before_request should never try to refresh access tokens.
+ # StaticCredentials intentionally does not support it.
+ @_helpers.copy_docstring(Credentials)
+ async def before_request(self, request, method, url, headers):
+ await self.apply(headers)
+
+
+class AnonymousCredentials(Credentials):
+ """Asynchronous Credentials that do not provide any authentication information.
+
+ These are useful in the case of services that support anonymous access or
+ local service emulators that do not use credentials.
+ """
+
+ async def refresh(self, request):
+ """Raises :class:``InvalidOperation``, anonymous credentials cannot be
+ refreshed."""
+ raise exceptions.InvalidOperation("Anonymous credentials cannot be refreshed.")
+
+ async def apply(self, headers, token=None):
+ """Anonymous credentials do nothing to the request.
+
+ The optional ``token`` argument is not supported.
+
+ Raises:
+ google.auth.exceptions.InvalidValue: If a token was specified.
+ """
+ if token is not None:
+ raise exceptions.InvalidValue("Anonymous credentials don't support tokens.")
+
+ async def before_request(self, request, method, url, headers):
+ """Anonymous credentials do nothing to the request."""
+ pass
diff --git a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
index e597365851..69b7b52458 100644
--- a/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
+++ b/contrib/python/google-auth/py3/google/auth/compute_engine/_metadata.py
@@ -28,11 +28,12 @@ from google.auth import _helpers
from google.auth import environment_vars
from google.auth import exceptions
from google.auth import metrics
+from google.auth._exponential_backoff import ExponentialBackoff
_LOGGER = logging.getLogger(__name__)
# Environment variable GCE_METADATA_HOST is originally named
-# GCE_METADATA_ROOT. For compatiblity reasons, here it checks
+# GCE_METADATA_ROOT. For compatibility reasons, here it checks
# the new variable first; if not set, the system falls back
# to the old variable.
_GCE_METADATA_HOST = os.getenv(environment_vars.GCE_METADATA_HOST, None)
@@ -119,11 +120,12 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
# could lead to false negatives in the event that we are on GCE, but
# the metadata resolution was particularly slow. The latter case is
# "unlikely".
- retries = 0
headers = _METADATA_HEADERS.copy()
headers[metrics.API_CLIENT_HEADER] = metrics.mds_ping()
- while retries < retry_count:
+ backoff = ExponentialBackoff(total_attempts=retry_count)
+
+ for attempt in backoff:
try:
response = request(
url=_METADATA_IP_ROOT, method="GET", headers=headers, timeout=timeout
@@ -139,11 +141,10 @@ def ping(request, timeout=_METADATA_DEFAULT_TIMEOUT, retry_count=3):
_LOGGER.warning(
"Compute Engine Metadata server unavailable on "
"attempt %s of %s. Reason: %s",
- retries + 1,
+ attempt,
retry_count,
e,
)
- retries += 1
return False
@@ -179,7 +180,7 @@ def get(
Returns:
Union[Mapping, str]: If the metadata server returns JSON, a mapping of
- the decoded JSON is return. Otherwise, the response content is
+ the decoded JSON is returned. Otherwise, the response content is
returned as a string.
Raises:
@@ -198,8 +199,9 @@ def get(
url = _helpers.update_query(base_url, query_params)
- retries = 0
- while retries < retry_count:
+ backoff = ExponentialBackoff(total_attempts=retry_count)
+
+ for attempt in backoff:
try:
response = request(url=url, method="GET", headers=headers_to_use)
break
@@ -208,11 +210,10 @@ def get(
_LOGGER.warning(
"Compute Engine Metadata server unavailable on "
"attempt %s of %s. Reason: %s",
- retries + 1,
+ attempt,
retry_count,
e,
)
- retries += 1
else:
raise exceptions.TransportError(
"Failed to retrieve {} from the Google Compute Engine "
diff --git a/contrib/python/google-auth/py3/google/auth/credentials.py b/contrib/python/google-auth/py3/google/auth/credentials.py
index 27abd443dc..e31930311b 100644
--- a/contrib/python/google-auth/py3/google/auth/credentials.py
+++ b/contrib/python/google-auth/py3/google/auth/credentials.py
@@ -22,12 +22,13 @@ import os
from google.auth import _helpers, environment_vars
from google.auth import exceptions
from google.auth import metrics
+from google.auth._credentials_base import _BaseCredentials
from google.auth._refresh_worker import RefreshThreadManager
DEFAULT_UNIVERSE_DOMAIN = "googleapis.com"
-class Credentials(metaclass=abc.ABCMeta):
+class Credentials(_BaseCredentials):
"""Base class for all credentials.
All credentials have a :attr:`token` that is used for authentication and
@@ -47,9 +48,8 @@ class Credentials(metaclass=abc.ABCMeta):
"""
def __init__(self):
- self.token = None
- """str: The bearer token that can be used in HTTP headers to make
- authenticated requests."""
+ super(Credentials, self).__init__()
+
self.expiry = None
"""Optional[datetime]: When the token expires and is no longer valid.
If this is None, the token is assumed to never expire."""
@@ -167,9 +167,7 @@ class Credentials(metaclass=abc.ABCMeta):
token (Optional[str]): If specified, overrides the current access
token.
"""
- headers["authorization"] = "Bearer {}".format(
- _helpers.from_bytes(token or self.token)
- )
+ self._apply(headers, token=token)
"""Trust boundary value will be a cached value from global lookup.
The response of trust boundary will be a list of regions and a hex
diff --git a/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py b/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py
new file mode 100644
index 0000000000..ec718d909a
--- /dev/null
+++ b/contrib/python/google-auth/py3/google/auth/transport/_requests_base.py
@@ -0,0 +1,52 @@
+# Copyright 2024 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.
+
+"""Transport adapter for Base Requests."""
+
+
+import abc
+
+
+_DEFAULT_TIMEOUT = 120 # in second
+
+
+class _BaseAuthorizedSession(metaclass=abc.ABCMeta):
+ """Base class for a Request Session with credentials. This class is intended to capture
+ the common logic between synchronous and asynchronous request sessions and is not intended to
+ be instantiated directly.
+
+ Args:
+ credentials (google.auth._credentials_base.BaseCredentials): The credentials to
+ add to the request.
+ """
+
+ def __init__(self, credentials):
+ self.credentials = credentials
+
+ @abc.abstractmethod
+ def request(
+ self,
+ method,
+ url,
+ data=None,
+ headers=None,
+ max_allowed_time=None,
+ timeout=_DEFAULT_TIMEOUT,
+ **kwargs
+ ):
+ raise NotImplementedError("Request must be implemented")
+
+ @abc.abstractmethod
+ def close(self):
+ raise NotImplementedError("Close must be implemented")
diff --git a/contrib/python/google-auth/py3/google/auth/transport/requests.py b/contrib/python/google-auth/py3/google/auth/transport/requests.py
index 23a69783dc..68f67c59bd 100644
--- a/contrib/python/google-auth/py3/google/auth/transport/requests.py
+++ b/contrib/python/google-auth/py3/google/auth/transport/requests.py
@@ -38,6 +38,7 @@ from google.auth import environment_vars
from google.auth import exceptions
from google.auth import transport
import google.auth.transport._mtls_helper
+from google.auth.transport._requests_base import _BaseAuthorizedSession
from google.oauth2 import service_account
_LOGGER = logging.getLogger(__name__)
@@ -292,7 +293,7 @@ class _MutualTlsOffloadAdapter(requests.adapters.HTTPAdapter):
return super(_MutualTlsOffloadAdapter, self).proxy_manager_for(*args, **kwargs)
-class AuthorizedSession(requests.Session):
+class AuthorizedSession(requests.Session, _BaseAuthorizedSession):
"""A Requests Session class with credentials.
This class is used to perform requests to API endpoints that require
@@ -389,7 +390,7 @@ class AuthorizedSession(requests.Session):
default_host=None,
):
super(AuthorizedSession, self).__init__()
- self.credentials = credentials
+ _BaseAuthorizedSession.__init__(self, credentials)
self._refresh_status_codes = refresh_status_codes
self._max_refresh_attempts = max_refresh_attempts
self._refresh_timeout = refresh_timeout
diff --git a/contrib/python/google-auth/py3/google/auth/version.py b/contrib/python/google-auth/py3/google/auth/version.py
index 51f7f62acd..c41f877658 100644
--- a/contrib/python/google-auth/py3/google/auth/version.py
+++ b/contrib/python/google-auth/py3/google/auth/version.py
@@ -12,4 +12,4 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-__version__ = "2.32.0"
+__version__ = "2.33.0"
diff --git a/contrib/python/google-auth/py3/google/oauth2/_client.py b/contrib/python/google-auth/py3/google/oauth2/_client.py
index bce797b88b..68e13ddc73 100644
--- a/contrib/python/google-auth/py3/google/oauth2/_client.py
+++ b/contrib/python/google-auth/py3/google/oauth2/_client.py
@@ -183,7 +183,11 @@ def _token_endpoint_request_no_throw(
if headers:
headers_to_use.update(headers)
- def _perform_request():
+ response_data = {}
+ retryable_error = False
+
+ retries = _exponential_backoff.ExponentialBackoff()
+ for _ in retries:
response = request(
method="POST", url=token_uri, headers=headers_to_use, body=body, **kwargs
)
@@ -192,7 +196,7 @@ def _token_endpoint_request_no_throw(
if hasattr(response.data, "decode")
else response.data
)
- response_data = ""
+
try:
# response_body should be a JSON
response_data = json.loads(response_body)
@@ -206,18 +210,8 @@ def _token_endpoint_request_no_throw(
status_code=response.status, response_data=response_data
)
- return False, response_data, retryable_error
-
- request_succeeded, response_data, retryable_error = _perform_request()
-
- if request_succeeded or not retryable_error or not can_retry:
- return request_succeeded, response_data, retryable_error
-
- retries = _exponential_backoff.ExponentialBackoff()
- for _ in retries:
- request_succeeded, response_data, retryable_error = _perform_request()
- if request_succeeded or not retryable_error:
- return request_succeeded, response_data, retryable_error
+ if not can_retry or not retryable_error:
+ return False, response_data, retryable_error
return False, response_data, retryable_error
diff --git a/contrib/python/google-auth/py3/google/oauth2/_client_async.py b/contrib/python/google-auth/py3/google/oauth2/_client_async.py
index 2858d862b0..8867f0a527 100644
--- a/contrib/python/google-auth/py3/google/oauth2/_client_async.py
+++ b/contrib/python/google-auth/py3/google/oauth2/_client_async.py
@@ -67,7 +67,11 @@ async def _token_endpoint_request_no_throw(
if access_token:
headers["Authorization"] = "Bearer {}".format(access_token)
- async def _perform_request():
+ response_data = {}
+ retryable_error = False
+
+ retries = _exponential_backoff.ExponentialBackoff()
+ for _ in retries:
response = await request(
method="POST", url=token_uri, headers=headers, body=body
)
@@ -93,18 +97,8 @@ async def _token_endpoint_request_no_throw(
status_code=response.status, response_data=response_data
)
- return False, response_data, retryable_error
-
- request_succeeded, response_data, retryable_error = await _perform_request()
-
- if request_succeeded or not retryable_error or not can_retry:
- return request_succeeded, response_data, retryable_error
-
- retries = _exponential_backoff.ExponentialBackoff()
- for _ in retries:
- request_succeeded, response_data, retryable_error = await _perform_request()
- if request_succeeded or not retryable_error:
- return request_succeeded, response_data, retryable_error
+ if not can_retry or not retryable_error:
+ return False, response_data, retryable_error
return False, response_data, retryable_error
diff --git a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
index 35e3c089f9..352342f150 100644
--- a/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
+++ b/contrib/python/google-auth/py3/tests/compute_engine/test__metadata.py
@@ -127,13 +127,15 @@ def test_ping_success_retry(mock_metrics_header_value):
assert request.call_count == 2
-def test_ping_failure_bad_flavor():
+@mock.patch("time.sleep", return_value=None)
+def test_ping_failure_bad_flavor(mock_sleep):
request = make_request("", headers={_metadata._METADATA_FLAVOR_HEADER: "meep"})
assert not _metadata.ping(request)
-def test_ping_failure_connection_failed():
+@mock.patch("time.sleep", return_value=None)
+def test_ping_failure_connection_failed(mock_sleep):
request = make_request("")
request.side_effect = exceptions.TransportError()
@@ -196,7 +198,8 @@ def test_get_success_json_content_type_charset():
assert result[key] == value
-def test_get_success_retry():
+@mock.patch("time.sleep", return_value=None)
+def test_get_success_retry(mock_sleep):
key, value = "foo", "bar"
data = json.dumps({key: value})
@@ -312,7 +315,8 @@ def _test_get_success_custom_root_old_variable():
)
-def test_get_failure():
+@mock.patch("time.sleep", return_value=None)
+def test_get_failure(mock_sleep):
request = make_request("Metadata error", status=http_client.NOT_FOUND)
with pytest.raises(exceptions.TransportError) as excinfo:
@@ -339,7 +343,8 @@ def test_get_return_none_for_not_found_error():
)
-def test_get_failure_connection_failed():
+@mock.patch("time.sleep", return_value=None)
+def test_get_failure_connection_failed(mock_sleep):
request = make_request("")
request.side_effect = exceptions.TransportError()
diff --git a/contrib/python/google-auth/py3/tests/oauth2/test__client.py b/contrib/python/google-auth/py3/tests/oauth2/test__client.py
index f9a2d3aff4..8736a4e27b 100644
--- a/contrib/python/google-auth/py3/tests/oauth2/test__client.py
+++ b/contrib/python/google-auth/py3/tests/oauth2/test__client.py
@@ -195,8 +195,8 @@ def test__token_endpoint_request_internal_failure_error():
_client._token_endpoint_request(
request, "http://example.com", {"error_description": "internal_failure"}
)
- # request should be called once and then with 3 retries
- assert request.call_count == 4
+ # request with 2 retries
+ assert request.call_count == 3
request = make_request(
{"error": "internal_failure"}, status=http_client.BAD_REQUEST
@@ -206,8 +206,8 @@ def test__token_endpoint_request_internal_failure_error():
_client._token_endpoint_request(
request, "http://example.com", {"error": "internal_failure"}
)
- # request should be called once and then with 3 retries
- assert request.call_count == 4
+ # request with 2 retries
+ assert request.call_count == 3
def test__token_endpoint_request_internal_failure_and_retry_failure_error():
@@ -626,6 +626,6 @@ def test__token_endpoint_request_no_throw_with_retry(can_retry):
)
if can_retry:
- assert mock_request.call_count == 4
+ assert mock_request.call_count == 3
else:
assert mock_request.call_count == 1
diff --git a/contrib/python/google-auth/py3/tests/test__exponential_backoff.py b/contrib/python/google-auth/py3/tests/test__exponential_backoff.py
index 06a54527e6..95422502b0 100644
--- a/contrib/python/google-auth/py3/tests/test__exponential_backoff.py
+++ b/contrib/python/google-auth/py3/tests/test__exponential_backoff.py
@@ -13,8 +13,10 @@
# limitations under the License.
import mock
+import pytest # type: ignore
from google.auth import _exponential_backoff
+from google.auth import exceptions
@mock.patch("time.sleep", return_value=None)
@@ -24,18 +26,31 @@ def test_exponential_backoff(mock_time):
iteration_count = 0
for attempt in eb:
- backoff_interval = mock_time.call_args[0][0]
- jitter = curr_wait * eb._randomization_factor
-
- assert (curr_wait - jitter) <= backoff_interval <= (curr_wait + jitter)
- assert attempt == iteration_count + 1
- assert eb.backoff_count == iteration_count + 1
- assert eb._current_wait_in_seconds == eb._multiplier ** (iteration_count + 1)
-
- curr_wait = eb._current_wait_in_seconds
+ if attempt == 1:
+ assert mock_time.call_count == 0
+ else:
+ backoff_interval = mock_time.call_args[0][0]
+ jitter = curr_wait * eb._randomization_factor
+
+ assert (curr_wait - jitter) <= backoff_interval <= (curr_wait + jitter)
+ assert attempt == iteration_count + 1
+ assert eb.backoff_count == iteration_count + 1
+ assert eb._current_wait_in_seconds == eb._multiplier ** iteration_count
+
+ curr_wait = eb._current_wait_in_seconds
iteration_count += 1
assert eb.total_attempts == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS
assert eb.backoff_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS
assert iteration_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS
- assert mock_time.call_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS
+ assert (
+ mock_time.call_count == _exponential_backoff._DEFAULT_RETRY_TOTAL_ATTEMPTS - 1
+ )
+
+
+def test_minimum_total_attempts():
+ with pytest.raises(exceptions.InvalidValue):
+ _exponential_backoff.ExponentialBackoff(total_attempts=0)
+ with pytest.raises(exceptions.InvalidValue):
+ _exponential_backoff.ExponentialBackoff(total_attempts=-1)
+ _exponential_backoff.ExponentialBackoff(total_attempts=1)
diff --git a/contrib/python/google-auth/py3/tests/test_credentials_async.py b/contrib/python/google-auth/py3/tests/test_credentials_async.py
new file mode 100644
index 0000000000..51e4f0611c
--- /dev/null
+++ b/contrib/python/google-auth/py3/tests/test_credentials_async.py
@@ -0,0 +1,136 @@
+# Copyright 2024 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.
+
+import pytest # type: ignore
+
+from google.auth import exceptions
+from google.auth.aio import credentials
+
+
+class CredentialsImpl(credentials.Credentials):
+ pass
+
+
+def test_credentials_constructor():
+ credentials = CredentialsImpl()
+ assert not credentials.token
+
+
+@pytest.mark.asyncio
+async def test_before_request():
+ credentials = CredentialsImpl()
+ request = "water"
+ headers = {}
+ credentials.token = "orchid"
+
+ # before_request should not affect the value of the token.
+ await credentials.before_request(request, "http://example.com", "GET", headers)
+ assert credentials.token == "orchid"
+ assert headers["authorization"] == "Bearer orchid"
+ assert "x-allowed-locations" not in headers
+
+ request = "earth"
+ headers = {}
+
+ # Second call shouldn't affect token or headers.
+ await credentials.before_request(request, "http://example.com", "GET", headers)
+ assert credentials.token == "orchid"
+ assert headers["authorization"] == "Bearer orchid"
+ assert "x-allowed-locations" not in headers
+
+
+@pytest.mark.asyncio
+async def test_static_credentials_ctor():
+ static_creds = credentials.StaticCredentials(token="orchid")
+ assert static_creds.token == "orchid"
+
+
+@pytest.mark.asyncio
+async def test_static_credentials_apply_default():
+ static_creds = credentials.StaticCredentials(token="earth")
+ headers = {}
+
+ await static_creds.apply(headers)
+ assert headers["authorization"] == "Bearer earth"
+
+ await static_creds.apply(headers, token="orchid")
+ assert headers["authorization"] == "Bearer orchid"
+
+
+@pytest.mark.asyncio
+async def test_static_credentials_before_request():
+ static_creds = credentials.StaticCredentials(token="orchid")
+ request = "water"
+ headers = {}
+
+ # before_request should not affect the value of the token.
+ await static_creds.before_request(request, "http://example.com", "GET", headers)
+ assert static_creds.token == "orchid"
+ assert headers["authorization"] == "Bearer orchid"
+ assert "x-allowed-locations" not in headers
+
+ request = "earth"
+ headers = {}
+
+ # Second call shouldn't affect token or headers.
+ await static_creds.before_request(request, "http://example.com", "GET", headers)
+ assert static_creds.token == "orchid"
+ assert headers["authorization"] == "Bearer orchid"
+ assert "x-allowed-locations" not in headers
+
+
+@pytest.mark.asyncio
+async def test_static_credentials_refresh():
+ static_creds = credentials.StaticCredentials(token="orchid")
+ request = "earth"
+
+ with pytest.raises(exceptions.InvalidOperation) as exc:
+ await static_creds.refresh(request)
+ assert exc.match("Static credentials cannot be refreshed.")
+
+
+@pytest.mark.asyncio
+async def test_anonymous_credentials_ctor():
+ anon = credentials.AnonymousCredentials()
+ assert anon.token is None
+
+
+@pytest.mark.asyncio
+async def test_anonymous_credentials_refresh():
+ anon = credentials.AnonymousCredentials()
+ request = object()
+ with pytest.raises(exceptions.InvalidOperation) as exc:
+ await anon.refresh(request)
+ assert exc.match("Anonymous credentials cannot be refreshed.")
+
+
+@pytest.mark.asyncio
+async def test_anonymous_credentials_apply_default():
+ anon = credentials.AnonymousCredentials()
+ headers = {}
+ await anon.apply(headers)
+ assert headers == {}
+ with pytest.raises(ValueError):
+ await anon.apply(headers, token="orchid")
+
+
+@pytest.mark.asyncio
+async def test_anonymous_credentials_before_request():
+ anon = credentials.AnonymousCredentials()
+ request = object()
+ method = "GET"
+ url = "https://example.com/api/endpoint"
+ headers = {}
+ await anon.before_request(request, method, url, headers)
+ assert headers == {}
diff --git a/contrib/python/google-auth/py3/ya.make b/contrib/python/google-auth/py3/ya.make
index 4ea57aefcc..caefae5db6 100644
--- a/contrib/python/google-auth/py3/ya.make
+++ b/contrib/python/google-auth/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(2.32.0)
+VERSION(2.33.0)
LICENSE(Apache-2.0)
@@ -28,6 +28,7 @@ PY_SRCS(
google/auth/__init__.py
google/auth/_cloud_sdk.py
google/auth/_credentials_async.py
+ google/auth/_credentials_base.py
google/auth/_default.py
google/auth/_default_async.py
google/auth/_exponential_backoff.py
@@ -36,6 +37,8 @@ PY_SRCS(
google/auth/_oauth2client.py
google/auth/_refresh_worker.py
google/auth/_service_account_info.py
+ google/auth/aio/__init__.py
+ google/auth/aio/credentials.py
google/auth/api_key.py
google/auth/app_engine.py
google/auth/aws.py
@@ -66,6 +69,7 @@ PY_SRCS(
google/auth/transport/_custom_tls_signer.py
google/auth/transport/_http_client.py
google/auth/transport/_mtls_helper.py
+ google/auth/transport/_requests_base.py
google/auth/transport/grpc.py
google/auth/transport/mtls.py
google/auth/transport/requests.py
diff --git a/contrib/python/hypothesis/py3/.dist-info/METADATA b/contrib/python/hypothesis/py3/.dist-info/METADATA
index e48da7dc0b..9a38b4132f 100644
--- a/contrib/python/hypothesis/py3/.dist-info/METADATA
+++ b/contrib/python/hypothesis/py3/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: hypothesis
-Version: 6.108.10
+Version: 6.110.0
Summary: A library for property-based testing
Home-page: https://hypothesis.works
Author: David R. MacIver and Zac Hatfield-Dodds
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/cathetus.py b/contrib/python/hypothesis/py3/hypothesis/internal/cathetus.py
index 30e0d214f1..1f8f2fe82b 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/cathetus.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/cathetus.py
@@ -27,7 +27,7 @@ def cathetus(h, a):
may be inaccurate up to a relative error of (around) floating-point
epsilon.
- Based on the C99 implementation https://github.com/jjgreen/cathetus
+ Based on the C99 implementation https://gitlab.com/jjg/cathetus
"""
if isnan(h):
return nan
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py
index 72bc4ba980..40aad2e850 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/data.py
@@ -679,6 +679,12 @@ class Examples:
i += n
return Example(self, i)
+ # not strictly necessary as we have len/getitem, but required for mypy.
+ # https://github.com/python/mypy/issues/9737
+ def __iter__(self) -> Iterator[Example]:
+ for i in range(len(self)):
+ yield self[i]
+
@dataclass_transform()
@attr.s(slots=True, frozen=True)
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py
index 4465f59e5c..39382637db 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/junkdrawer.py
@@ -19,12 +19,14 @@ import time
import warnings
from random import Random
from typing import (
+ Any,
Callable,
Dict,
Generic,
Iterable,
Iterator,
List,
+ Literal,
Optional,
Sequence,
Tuple,
@@ -109,10 +111,10 @@ class IntList(Sequence[int]):
def count(self, value: int) -> int:
return self.__underlying.count(value)
- def __repr__(self):
+ def __repr__(self) -> str:
return f"IntList({list(self.__underlying)!r})"
- def __len__(self):
+ def __len__(self) -> int:
return len(self.__underlying)
@overload
@@ -305,7 +307,7 @@ class ensure_free_stackframes:
a reasonable value of N).
"""
- def __enter__(self):
+ def __enter__(self) -> None:
cur_depth = stack_depth_of_caller()
self.old_maxdepth = sys.getrecursionlimit()
# The default CPython recursionlimit is 1000, but pytest seems to bump
@@ -418,8 +420,8 @@ class SelfOrganisingList(Generic[T]):
_gc_initialized = False
-_gc_start = 0
-_gc_cumulative_time = 0
+_gc_start: float = 0
+_gc_cumulative_time: float = 0
# Since gc_callback potentially runs in test context, and perf_counter
# might be monkeypatched, we store a reference to the real one.
@@ -431,7 +433,9 @@ def gc_cumulative_time() -> float:
if not _gc_initialized:
if hasattr(gc, "callbacks"):
# CPython
- def gc_callback(phase, info):
+ def gc_callback(
+ phase: Literal["start", "stop"], info: Dict[str, int]
+ ) -> None:
global _gc_start, _gc_cumulative_time
try:
now = _perf_counter()
@@ -453,7 +457,7 @@ def gc_cumulative_time() -> float:
gc.callbacks.insert(0, gc_callback)
elif hasattr(gc, "hooks"): # pragma: no cover # pypy only
# PyPy
- def hook(stats):
+ def hook(stats: Any) -> None:
global _gc_cumulative_time
try:
_gc_cumulative_time += stats.duration
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/optimiser.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/optimiser.py
index 2f8f761223..a8f4478453 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/optimiser.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/optimiser.py
@@ -8,9 +8,11 @@
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
+from typing import Union
+
from hypothesis.internal.compat import int_from_bytes, int_to_bytes
-from hypothesis.internal.conjecture.data import Status
-from hypothesis.internal.conjecture.engine import BUFFER_SIZE
+from hypothesis.internal.conjecture.data import ConjectureResult, Status, _Overrun
+from hypothesis.internal.conjecture.engine import BUFFER_SIZE, ConjectureRunner
from hypothesis.internal.conjecture.junkdrawer import find_integer
from hypothesis.internal.conjecture.pareto import NO_SCORE
@@ -31,7 +33,13 @@ class Optimiser:
Software Testing and Analysis. ACM, 2017.
"""
- def __init__(self, engine, data, target, max_improvements=100):
+ def __init__(
+ self,
+ engine: ConjectureRunner,
+ data: ConjectureResult,
+ target: str,
+ max_improvements: int = 100,
+ ) -> None:
"""Optimise ``target`` starting from ``data``. Will stop either when
we seem to have found a local maximum or when the target score has
been improved ``max_improvements`` times. This limit is in place to
@@ -42,21 +50,22 @@ class Optimiser:
self.max_improvements = max_improvements
self.improvements = 0
- def run(self):
+ def run(self) -> None:
self.hill_climb()
- def score_function(self, data):
+ def score_function(self, data: ConjectureResult) -> float:
return data.target_observations.get(self.target, NO_SCORE)
@property
- def current_score(self):
+ def current_score(self) -> float:
return self.score_function(self.current_data)
- def consider_new_test_data(self, data):
+ def consider_new_data(self, data: Union[ConjectureResult, _Overrun]) -> bool:
"""Consider a new data object as a candidate target. If it is better
than the current one, return True."""
if data.status < Status.VALID:
return False
+ assert isinstance(data, ConjectureResult)
score = self.score_function(data)
if score < self.current_score:
return False
@@ -73,7 +82,7 @@ class Optimiser:
return True
return False
- def hill_climb(self):
+ def hill_climb(self) -> None:
"""The main hill climbing loop where we actually do the work: Take
data, and attempt to improve its score for target. select_example takes
a data object and returns an index to an example where we should focus
@@ -104,7 +113,7 @@ class Optimiser:
if existing_as_int == max_int_value:
continue
- def attempt_replace(v):
+ def attempt_replace(v: int) -> bool:
"""Try replacing the current block in the current best test case
with an integer of value i. Note that we use the *current*
best and not the one we started with. This helps ensure that
@@ -126,12 +135,14 @@ class Optimiser:
+ bytes(BUFFER_SIZE),
)
- if self.consider_new_test_data(attempt):
+ if self.consider_new_data(attempt):
return True
- if attempt.status < Status.INVALID or len(attempt.buffer) == len(
- self.current_data.buffer
- ):
+ if attempt.status == Status.OVERRUN:
+ return False
+
+ assert isinstance(attempt, ConjectureResult)
+ if len(attempt.buffer) == len(self.current_data.buffer):
return False
for i, ex in enumerate(self.current_data.examples):
@@ -143,7 +154,7 @@ class Optimiser:
if ex.length == ex_attempt.length:
continue # pragma: no cover
replacement = attempt.buffer[ex_attempt.start : ex_attempt.end]
- if self.consider_new_test_data(
+ if self.consider_new_data(
self.engine.cached_test_function(
prefix
+ replacement
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py
index a004338372..d441821787 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinker.py
@@ -9,7 +9,7 @@
# obtain one at https://mozilla.org/MPL/2.0/.
from collections import defaultdict
-from typing import TYPE_CHECKING, Callable, Dict, Optional, Union
+from typing import TYPE_CHECKING, Callable, Dict, Optional, Tuple, TypeVar, Union
import attr
@@ -38,10 +38,14 @@ from hypothesis.internal.conjecture.shrinking import (
)
if TYPE_CHECKING:
+ from random import Random
+
from hypothesis.internal.conjecture.engine import ConjectureRunner
+SortKeyT = TypeVar("SortKeyT", str, bytes)
+
-def sort_key(buffer):
+def sort_key(buffer: SortKeyT) -> Tuple[int, SortKeyT]:
"""Returns a sort key such that "simpler" buffers are smaller than
"more complicated" ones.
@@ -357,16 +361,16 @@ class Shrinker:
return self.passes_by_name[name]
@property
- def calls(self):
+ def calls(self) -> int:
"""Return the number of calls that have been made to the underlying
test function."""
return self.engine.call_count
@property
- def misaligned(self):
+ def misaligned(self) -> int:
return self.engine.misaligned_count
- def check_calls(self):
+ def check_calls(self) -> None:
if self.calls - self.calls_at_last_shrink >= self.max_stall:
raise StopShrinking
@@ -449,11 +453,11 @@ class Shrinker:
self.check_calls()
return result
- def debug(self, msg):
+ def debug(self, msg: str) -> None:
self.engine.debug(msg)
@property
- def random(self):
+ def random(self) -> "Random":
return self.engine.random
def shrink(self):
@@ -1068,10 +1072,11 @@ class Shrinker:
if node.was_forced:
return False # pragma: no cover
- if node.ir_type == "string":
+ if node.ir_type in {"string", "bytes"}:
+ size_kwarg = "min_size" if node.ir_type == "string" else "size"
# if the size *increased*, we would have to guess what to pad with
# in order to try fixing up this attempt. Just give up.
- if node.kwargs["min_size"] <= attempt_kwargs["min_size"]:
+ if node.kwargs[size_kwarg] <= attempt_kwargs[size_kwarg]:
return False
# the size decreased in our attempt. Try again, but replace with
# the min_size that we would have gotten, and truncate the value
@@ -1082,22 +1087,7 @@ class Shrinker:
initial_attempt[node.index].copy(
with_kwargs=attempt_kwargs,
with_value=initial_attempt[node.index].value[
- : attempt_kwargs["min_size"]
- ],
- )
- ]
- + initial_attempt[node.index :]
- )
- if node.ir_type == "bytes":
- if node.kwargs["size"] <= attempt_kwargs["size"]:
- return False
- return self.consider_new_tree(
- initial_attempt[: node.index]
- + [
- initial_attempt[node.index].copy(
- with_kwargs=attempt_kwargs,
- with_value=initial_attempt[node.index].value[
- : attempt_kwargs["size"]
+ : attempt_kwargs[size_kwarg]
],
)
]
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py
index 1de89bd18b..b0c5ec8694 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/conjecture/shrinking/common.py
@@ -38,10 +38,10 @@ class Shrinker:
self.debugging_enabled = debug
@property
- def calls(self):
+ def calls(self) -> int:
return len(self.__seen)
- def __repr__(self):
+ def __repr__(self) -> str:
return "{}({}initial={!r}, current={!r})".format(
type(self).__name__,
"" if self.name is None else f"{self.name!r}, ",
@@ -75,7 +75,7 @@ class Shrinker:
return other_class.shrink(initial, predicate, **kwargs)
- def debug(self, *args):
+ def debug(self, *args: object) -> None:
if self.debugging_enabled:
print("DEBUG", self, *args)
diff --git a/contrib/python/hypothesis/py3/hypothesis/internal/floats.py b/contrib/python/hypothesis/py3/hypothesis/internal/floats.py
index 6c4210e997..79e6433dca 100644
--- a/contrib/python/hypothesis/py3/hypothesis/internal/floats.py
+++ b/contrib/python/hypothesis/py3/hypothesis/internal/floats.py
@@ -11,22 +11,50 @@
import math
import struct
from sys import float_info
-from typing import Callable, Optional, SupportsFloat
+from typing import (
+ TYPE_CHECKING,
+ Callable,
+ Dict,
+ Literal,
+ Optional,
+ SupportsFloat,
+ Tuple,
+ Union,
+)
+
+if TYPE_CHECKING:
+ from typing import TypeAlias
+else:
+ TypeAlias = object
+
+SignedIntFormat: "TypeAlias" = Literal["!h", "!i", "!q"]
+UnsignedIntFormat: "TypeAlias" = Literal["!H", "!I", "!Q"]
+IntFormat: "TypeAlias" = Union[SignedIntFormat, UnsignedIntFormat]
+FloatFormat: "TypeAlias" = Literal["!e", "!f", "!d"]
+Width: "TypeAlias" = Literal[16, 32, 64]
# Format codes for (int, float) sized types, used for byte-wise casts.
# See https://docs.python.org/3/library/struct.html#format-characters
-STRUCT_FORMATS = {
+STRUCT_FORMATS: Dict[int, Tuple[UnsignedIntFormat, FloatFormat]] = {
16: ("!H", "!e"),
32: ("!I", "!f"),
64: ("!Q", "!d"),
}
+TO_SIGNED_FORMAT: Dict[UnsignedIntFormat, SignedIntFormat] = {
+ "!H": "!h",
+ "!I": "!i",
+ "!Q": "!q",
+}
+
-def reinterpret_bits(x, from_, to):
- return struct.unpack(to, struct.pack(from_, x))[0]
+def reinterpret_bits(x: float, from_: str, to: str) -> float:
+ x = struct.unpack(to, struct.pack(from_, x))[0]
+ assert isinstance(x, (float, int))
+ return x
-def float_of(x, width):
+def float_of(x: SupportsFloat, width: Width) -> float:
assert width in (16, 32, 64)
if width == 64:
return float(x)
@@ -45,7 +73,7 @@ def is_negative(x: SupportsFloat) -> bool:
) from None
-def count_between_floats(x, y, width=64):
+def count_between_floats(x: float, y: float, width: int = 64) -> int:
assert x <= y
if is_negative(x):
if is_negative(y):
@@ -59,17 +87,19 @@ def count_between_floats(x, y, width=64):
return float_to_int(y, width) - float_to_int(x, width) + 1
-def float_to_int(value, width=64):
+def float_to_int(value: float, width: int = 64) -> int:
fmt_int, fmt_flt = STRUCT_FORMATS[width]
- return reinterpret_bits(value, fmt_flt, fmt_int)
+ x = reinterpret_bits(value, fmt_flt, fmt_int)
+ assert isinstance(x, int)
+ return x
-def int_to_float(value, width=64):
+def int_to_float(value: int, width: int = 64) -> float:
fmt_int, fmt_flt = STRUCT_FORMATS[width]
return reinterpret_bits(value, fmt_int, fmt_flt)
-def next_up(value, width=64):
+def next_up(value: float, width: int = 64) -> float:
"""Return the first float larger than finite `val` - IEEE 754's `nextUp`.
From https://stackoverflow.com/a/10426033, with thanks to Mark Dickinson.
@@ -81,34 +111,34 @@ def next_up(value, width=64):
return 0.0
fmt_int, fmt_flt = STRUCT_FORMATS[width]
# Note: n is signed; float_to_int returns unsigned
- fmt_int = fmt_int.lower()
- n = reinterpret_bits(value, fmt_flt, fmt_int)
+ fmt_int_signed = TO_SIGNED_FORMAT[fmt_int]
+ n = reinterpret_bits(value, fmt_flt, fmt_int_signed)
if n >= 0:
n += 1
else:
n -= 1
- return reinterpret_bits(n, fmt_int, fmt_flt)
+ return reinterpret_bits(n, fmt_int_signed, fmt_flt)
-def next_down(value, width=64):
+def next_down(value: float, width: int = 64) -> float:
return -next_up(-value, width)
-def next_down_normal(value, width, allow_subnormal):
+def next_down_normal(value: float, width: int, *, allow_subnormal: bool) -> float:
value = next_down(value, width)
if (not allow_subnormal) and 0 < abs(value) < width_smallest_normals[width]:
return 0.0 if value > 0 else -width_smallest_normals[width]
return value
-def next_up_normal(value, width, allow_subnormal):
- return -next_down_normal(-value, width, allow_subnormal)
+def next_up_normal(value: float, width: int, *, allow_subnormal: bool) -> float:
+ return -next_down_normal(-value, width, allow_subnormal=allow_subnormal)
# Smallest positive non-zero numbers that is fully representable by an
# IEEE-754 float, calculated with the width's associated minimum exponent.
# Values from https://en.wikipedia.org/wiki/IEEE_754#Basic_and_interchange_formats
-width_smallest_normals = {
+width_smallest_normals: Dict[int, float] = {
16: 2 ** -(2 ** (5 - 1) - 2),
32: 2 ** -(2 ** (8 - 1) - 2),
64: 2 ** -(2 ** (11 - 1) - 2),
diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
index 62dcecde20..7fdeedb497 100644
--- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
+++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/core.py
@@ -1295,6 +1295,12 @@ def _from_type(thing: Type[Ex]) -> SearchStrategy[Ex]:
if types.is_a_union(thing):
args = sorted(thing.__args__, key=types.type_sorting_key)
return one_of([_from_type(t) for t in args])
+ if thing in types.LiteralStringTypes: # pragma: no cover
+ # We can't really cover this because it needs either
+ # typing-extensions or python3.11+ typing.
+ # `LiteralString` from runtime's point of view is just a string.
+ # Fallback to regular text.
+ return text()
# We also have a special case for TypeVars.
# They are represented as instances like `~T` when they come here.
# We need to work with their type instead.
@@ -1340,27 +1346,68 @@ def _from_type(thing: Type[Ex]) -> SearchStrategy[Ex]:
or hasattr(types.typing_extensions, "_TypedDictMeta") # type: ignore
and type(thing) is types.typing_extensions._TypedDictMeta # type: ignore
): # pragma: no cover
+
+ def _get_annotation_arg(key, annotation_type):
+ try:
+ return get_args(annotation_type)[0]
+ except IndexError:
+ raise InvalidArgument(
+ f"`{key}: {annotation_type.__name__}` is not a valid type annotation"
+ ) from None
+
+ # Taken from `Lib/typing.py` and modified:
+ def _get_typeddict_qualifiers(key, annotation_type):
+ qualifiers = []
+ while True:
+ annotation_origin = types.extended_get_origin(annotation_type)
+ if annotation_origin in types.AnnotatedTypes:
+ if annotation_args := get_args(annotation_type):
+ annotation_type = annotation_args[0]
+ else:
+ break
+ elif annotation_origin in types.RequiredTypes:
+ qualifiers.append(types.RequiredTypes)
+ annotation_type = _get_annotation_arg(key, annotation_type)
+ elif annotation_origin in types.NotRequiredTypes:
+ qualifiers.append(types.NotRequiredTypes)
+ annotation_type = _get_annotation_arg(key, annotation_type)
+ elif annotation_origin in types.ReadOnlyTypes:
+ qualifiers.append(types.ReadOnlyTypes)
+ annotation_type = _get_annotation_arg(key, annotation_type)
+ else:
+ break
+ return set(qualifiers), annotation_type
+
# The __optional_keys__ attribute may or may not be present, but if there's no
# way to tell and we just have to assume that everything is required.
# See https://github.com/python/cpython/pull/17214 for details.
optional = set(getattr(thing, "__optional_keys__", ()))
+ required = set(
+ getattr(thing, "__required_keys__", get_type_hints(thing).keys())
+ )
anns = {}
for k, v in get_type_hints(thing).items():
- origin = get_origin(v)
- if origin in types.RequiredTypes + types.NotRequiredTypes:
- if origin in types.NotRequiredTypes:
- optional.add(k)
- else:
- optional.discard(k)
- try:
- v = v.__args__[0]
- except IndexError:
- raise InvalidArgument(
- f"`{k}: {v.__name__}` is not a valid type annotation"
- ) from None
+ qualifiers, v = _get_typeddict_qualifiers(k, v)
+ # We ignore `ReadOnly` type for now, only unwrap it.
+ if types.RequiredTypes in qualifiers:
+ optional.discard(k)
+ required.add(k)
+ if types.NotRequiredTypes in qualifiers:
+ optional.add(k)
+ required.discard(k)
+
anns[k] = from_type_guarded(v)
if anns[k] is ...:
anns[k] = _from_type_deferred(v)
+
+ if not required.isdisjoint(optional): # pragma: no cover
+ # It is impossible to cover, because `typing.py` or `typing-extensions`
+ # won't allow creating incorrect TypedDicts,
+ # this is just a sanity check from our side.
+ raise InvalidArgument(
+ f"Required keys overlap with optional keys in a TypedDict:"
+ f" {required=}, {optional=}"
+ )
if (
(not anns)
and thing.__annotations__
@@ -1368,7 +1415,7 @@ def _from_type(thing: Type[Ex]) -> SearchStrategy[Ex]:
):
raise InvalidArgument("Failed to retrieve type annotations for local type")
return fixed_dictionaries( # type: ignore
- mapping={k: v for k, v in anns.items() if k not in optional},
+ mapping={k: v for k, v in anns.items() if k in required},
optional={k: v for k, v in anns.items() if k in optional},
)
diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/numbers.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/numbers.py
index 507cf879d6..033577f2c8 100644
--- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/numbers.py
+++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/numbers.py
@@ -380,22 +380,30 @@ def floats(
if min_value is not None and (
exclude_min or (min_arg is not None and min_value < min_arg)
):
- min_value = next_up_normal(min_value, width, assumed_allow_subnormal)
+ min_value = next_up_normal(
+ min_value, width, allow_subnormal=assumed_allow_subnormal
+ )
if min_value == min_arg:
assert min_value == min_arg == 0
assert is_negative(min_arg)
assert not is_negative(min_value)
- min_value = next_up_normal(min_value, width, assumed_allow_subnormal)
+ min_value = next_up_normal(
+ min_value, width, allow_subnormal=assumed_allow_subnormal
+ )
assert min_value > min_arg # type: ignore
if max_value is not None and (
exclude_max or (max_arg is not None and max_value > max_arg)
):
- max_value = next_down_normal(max_value, width, assumed_allow_subnormal)
+ max_value = next_down_normal(
+ max_value, width, allow_subnormal=assumed_allow_subnormal
+ )
if max_value == max_arg:
assert max_value == max_arg == 0
assert is_negative(max_value)
assert not is_negative(max_arg)
- max_value = next_down_normal(max_value, width, assumed_allow_subnormal)
+ max_value = next_down_normal(
+ max_value, width, allow_subnormal=assumed_allow_subnormal
+ )
assert max_value < max_arg # type: ignore
if min_value == -math.inf:
diff --git a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py
index 8753bfb784..d5fef48aad 100644
--- a/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py
+++ b/contrib/python/hypothesis/py3/hypothesis/strategies/_internal/types.py
@@ -147,6 +147,49 @@ except AttributeError: # pragma: no cover
pass # `typing_extensions` might not be installed
+ReadOnlyTypes: tuple = ()
+try:
+ ReadOnlyTypes += (typing.ReadOnly,) # type: ignore
+except AttributeError: # pragma: no cover
+ pass # Is missing for `python<3.13`
+try:
+ ReadOnlyTypes += (typing_extensions.ReadOnly,)
+except AttributeError: # pragma: no cover
+ pass # `typing_extensions` might not be installed
+
+
+AnnotatedTypes: tuple = ()
+try:
+ AnnotatedTypes += (typing.Annotated,)
+except AttributeError: # pragma: no cover
+ pass # Is missing for `python<3.9`
+try:
+ AnnotatedTypes += (typing_extensions.Annotated,)
+except AttributeError: # pragma: no cover
+ pass # `typing_extensions` might not be installed
+
+
+LiteralStringTypes: tuple = ()
+try:
+ LiteralStringTypes += (typing.LiteralString,) # type: ignore
+except AttributeError: # pragma: no cover
+ pass # Is missing for `python<3.11`
+try:
+ LiteralStringTypes += (typing_extensions.LiteralString,)
+except AttributeError: # pragma: no cover
+ pass # `typing_extensions` might not be installed
+
+
+# We need this function to use `get_origin` on 3.8 for types added later:
+# in typing-extensions, so we prefer this function over regular `get_origin`
+# when unwrapping `TypedDict`'s annotations.
+try:
+ extended_get_origin = typing_extensions.get_origin
+except AttributeError: # pragma: no cover
+ # `typing_extensions` might not be installed, in this case - fallback:
+ extended_get_origin = get_origin # type: ignore
+
+
# We use this variable to be sure that we are working with a type from `typing`:
typing_root_type = (typing._Final, typing._GenericAlias) # type: ignore
@@ -169,10 +212,10 @@ for name in (
"Self",
"Required",
"NotRequired",
+ "ReadOnly",
"Never",
"TypeVarTuple",
"Unpack",
- "LiteralString",
):
try:
NON_RUNTIME_TYPES += (getattr(typing, name),)
diff --git a/contrib/python/hypothesis/py3/hypothesis/version.py b/contrib/python/hypothesis/py3/hypothesis/version.py
index c8a8221c54..007af37ae6 100644
--- a/contrib/python/hypothesis/py3/hypothesis/version.py
+++ b/contrib/python/hypothesis/py3/hypothesis/version.py
@@ -8,5 +8,5 @@
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
# obtain one at https://mozilla.org/MPL/2.0/.
-__version_info__ = (6, 108, 10)
+__version_info__ = (6, 110, 0)
__version__ = ".".join(map(str, __version_info__))
diff --git a/contrib/python/hypothesis/py3/ya.make b/contrib/python/hypothesis/py3/ya.make
index 8a025cf359..7e33dc4497 100644
--- a/contrib/python/hypothesis/py3/ya.make
+++ b/contrib/python/hypothesis/py3/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(6.108.10)
+VERSION(6.110.0)
LICENSE(MPL-2.0)