diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-11 07:47:47 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-04-11 07:55:01 +0300 |
commit | f23341d903ec562ebc7da4b59f59fe5c06a8522c (patch) | |
tree | 2a07040f1adcfdc4dde40a41928a35c11b82ce77 /contrib/python/requests-mock/py3 | |
parent | ca7c60d70c549b4464557560f4d6761a3cb1aefe (diff) | |
download | ydb-f23341d903ec562ebc7da4b59f59fe5c06a8522c.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/python/requests-mock/py3')
11 files changed, 60 insertions, 154 deletions
diff --git a/contrib/python/requests-mock/py3/.dist-info/METADATA b/contrib/python/requests-mock/py3/.dist-info/METADATA index d8eadeaec2..6ce8ea41a6 100644 --- a/contrib/python/requests-mock/py3/.dist-info/METADATA +++ b/contrib/python/requests-mock/py3/.dist-info/METADATA @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: requests-mock -Version: 1.11.0 +Version: 1.12.0 Summary: Mock out responses from the requests package Home-page: https://requests-mock.readthedocs.io/ Author: Jamie Lennox @@ -13,32 +13,19 @@ Classifier: Intended Audience :: Information Technology Classifier: License :: OSI Approved :: Apache Software License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.4 -Classifier: Programming Language :: Python :: 3.5 -Classifier: Programming Language :: Python :: 3.6 -Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 Classifier: Programming Language :: Python :: Implementation :: CPython Classifier: Programming Language :: Python :: Implementation :: PyPy Classifier: Topic :: Software Development :: Testing License-File: LICENSE -Requires-Dist: requests (<3,>=2.3) -Requires-Dist: six +Requires-Dist: requests <3,>=2.22 Provides-Extra: fixture Requires-Dist: fixtures ; extra == 'fixture' -Provides-Extra: test -Requires-Dist: fixtures ; extra == 'test' -Requires-Dist: purl ; extra == 'test' -Requires-Dist: pytest ; extra == 'test' -Requires-Dist: sphinx ; extra == 'test' -Requires-Dist: testtools ; extra == 'test' -Requires-Dist: requests-futures ; extra == 'test' -Requires-Dist: mock ; (( python_version < '3.3')) and extra == 'test' =============================== requests-mock @@ -141,4 +128,3 @@ under the License. .. _docs: https://requests-mock.readthedocs.io/ .. _GitHub: https://github.com/jamielennox/requests-mock .. _StackOverflow: https://stackoverflow.com/questions/tagged/requests-mock - diff --git a/contrib/python/requests-mock/py3/AUTHORS b/contrib/python/requests-mock/py3/AUTHORS deleted file mode 100644 index ae2e02a612..0000000000 --- a/contrib/python/requests-mock/py3/AUTHORS +++ /dev/null @@ -1,50 +0,0 @@ -Adam Johnson <me@adamj.eu> -Alex Peters <alex@peters.net> -Allan Lewis <allanlewis99@gmail.com> -Andreas Jaeger <aj@suse.com> -Andrii Oriekhov <andriyorehov@gmail.com> -Arjan Keeman <arjan.keeman@falckon.nl> -Axel H <noirbizarre@users.noreply.github.com> -Christian Clauss <cclauss@me.com> -Colas Le Guernic <clslgrnc@users.noreply.github.com> -Cyrille Corpet <cyrille@bayesimpact.org> -Darragh Bailey <dbailey@hpe.com> -David Kremer <courrier@david-kremer.fr> -Ian Cordasco <ian.cordasco@rackspace.com> -Ilya Konstantinov <ilya.konstantinov@gmail.com> -Jamie Lennox <jamie.lennox@agoda.com> -Jamie Lennox <jamie@vibrato.com.au> -Jamie Lennox <jamielennox@gmail.com> -Jamie Lennox <jamielennox@redhat.com> -Janne Pulkkinen <janne.pulkkinen@protonmail.com> -Janonymous <janonymous.codevulture@gmail.com> -Jelle van der Waa <jelle@archlinux.org> -Jeremy Stanley <fungi@yuggoth.org> -Jochen Kupperschmidt <homework@nwsnet.de> -Joel Andrews <oldsneerjaw@gmail.com> -Jon Dufresne <jon.dufresne@gmail.com> -Kenny Nguyen <kkenny.nguyen@pm.me> -Louis Taylor <louis@kragniz.eu> -Manuel Kaufmann <humitos@gmail.com> -Matthias Bilger <matthias@bilger.info> -Michał Górny <mgorny@gentoo.org> -Miroslav Šedivý <6774676+eumiro@users.noreply.github.com> -Monty Taylor <mordred@inaugust.com> -Noam <noamkush@gmail.com> -Pascal Corpet <pascal@bayesimpact.org> -Peter Hodge <peter.hodge84@gmail.com> -Petre Mierlutiu <petrem@users.noreply.github.com> -Rick van de Loo <rickvandeloo@gmail.com> -Ryan Brooke Payne <ryan.payne@daveramsey.com> -Sebastian Kalinowski <sebastian@kalinowski.eu> -Simon Willison <swillison@gmail.com> -Stefaan Lippens <stefaan.lippens@vito.be> -Swapnil Kulkarni (coolsvap) <me@coolsvap.net> -Ville Skyttä <ville.skytta@iki.fi> -boncheff <boncheff@users.noreply.github.com> -clslgrnc <clslgrnc@users.noreply.github.com> -dongfangtianyu <7629022+dongfangtianyu@users.noreply.github.com> -popokatapepel <jan-seins@hotmail.de> -reedip <reedip.banerjee@nectechnologies.in> -rfportilla <rfportilla@yahoo.com> -voith <voithjm1@gmail.com> diff --git a/contrib/python/requests-mock/py3/requests_mock/adapter.py b/contrib/python/requests-mock/py3/requests_mock/adapter.py index e0560b2226..b6f00529ee 100644 --- a/contrib/python/requests-mock/py3/requests_mock/adapter.py +++ b/contrib/python/requests-mock/py3/requests_mock/adapter.py @@ -10,12 +10,11 @@ # License for the specific language governing permissions and limitations # under the License. +import urllib.parse import weakref from requests.adapters import BaseAdapter from requests.utils import requote_uri -import six -from six.moves.urllib import parse as urlparse from requests_mock import exceptions from requests_mock.request import _RequestObjectProxy @@ -99,8 +98,8 @@ class _Matcher(_RequestHistoryTracker): self._additional_matcher = additional_matcher # url can be a regex object or ANY so don't always run urlparse - if isinstance(url, six.string_types): - url_parts = urlparse.urlparse(url) + if isinstance(url, str): + url_parts = urllib.parse.urlparse(url) self._scheme = url_parts.scheme.lower() self._netloc = url_parts.netloc.lower() self._path = requote_uri(url_parts.path or '/') @@ -155,10 +154,11 @@ class _Matcher(_RequestHistoryTracker): return False # construct our own qs structure as we remove items from it below - request_qs = urlparse.parse_qs(request.query, keep_blank_values=True) - matcher_qs = urlparse.parse_qs(self._query, keep_blank_values=True) + request_qs = urllib.parse.parse_qs(request.query, + keep_blank_values=True) + matcher_qs = urllib.parse.parse_qs(self._query, keep_blank_values=True) - for k, vals in six.iteritems(matcher_qs): + for k, vals in matcher_qs.items(): for v in vals: try: request_qs.get(k, []).remove(v) @@ -166,14 +166,14 @@ class _Matcher(_RequestHistoryTracker): return False if self._complete_qs: - for v in six.itervalues(request_qs): + for v in request_qs.values(): if v: return False return True def _match_headers(self, request): - for k, vals in six.iteritems(self._request_headers): + for k, vals in self._request_headers.items(): try: header = request.headers[k] @@ -182,7 +182,7 @@ class _Matcher(_RequestHistoryTracker): # difference, in 2 they are just whatever the user inputted in # 1 they are bytes. Let's optionally handle both and look at # removing this when we depend on requests 2. - if not isinstance(k, six.text_type): + if not isinstance(k, str): return False try: diff --git a/contrib/python/requests-mock/py3/requests_mock/adapter.pyi b/contrib/python/requests-mock/py3/requests_mock/adapter.pyi index dbeba496ba..b793a928fc 100644 --- a/contrib/python/requests-mock/py3/requests_mock/adapter.pyi +++ b/contrib/python/requests-mock/py3/requests_mock/adapter.pyi @@ -66,7 +66,7 @@ class Adapter(BaseAdapter, _RequestHistoryTracker): text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., **kwargs: Any diff --git a/contrib/python/requests-mock/py3/requests_mock/compat.py b/contrib/python/requests-mock/py3/requests_mock/compat.py deleted file mode 100644 index 8b6293af15..0000000000 --- a/contrib/python/requests-mock/py3/requests_mock/compat.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 -# -# https://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. - - -class _FakeHTTPMessage(object): - - def __init__(self, headers): - self.headers = headers - - def getheaders(self, name): - try: - return [self.headers[name]] - except KeyError: - return [] - - def get_all(self, name, failobj=None): - # python 3 only, overrides email.message.Message.get_all - try: - return [self.headers[name]] - except KeyError: - return failobj diff --git a/contrib/python/requests-mock/py3/requests_mock/mocker.py b/contrib/python/requests-mock/py3/requests_mock/mocker.py index d3bc85538e..3a7be37880 100644 --- a/contrib/python/requests-mock/py3/requests_mock/mocker.py +++ b/contrib/python/requests-mock/py3/requests_mock/mocker.py @@ -17,7 +17,6 @@ import threading import types import requests -import six from requests_mock import adapter from requests_mock import exceptions @@ -60,8 +59,9 @@ def _is_bound_method(method): bound_method 's self is a obj unbound_method 's self is None """ - if isinstance(method, types.MethodType) and six.get_method_self(method): + if isinstance(method, types.MethodType) and hasattr(method, '__self__'): return True + return False @@ -74,7 +74,7 @@ def _set_method(target, name, method): If method is a bound_method, can direct setattr """ if not isinstance(target, type) and not _is_bound_method(method): - method = six.create_bound_method(method, target) + method = types.MethodType(method, target) setattr(target, name, method) diff --git a/contrib/python/requests-mock/py3/requests_mock/mocker.pyi b/contrib/python/requests-mock/py3/requests_mock/mocker.pyi index 891e7d6c9a..e2008446ef 100644 --- a/contrib/python/requests-mock/py3/requests_mock/mocker.pyi +++ b/contrib/python/requests-mock/py3/requests_mock/mocker.pyi @@ -3,7 +3,7 @@ from json import JSONEncoder from http.cookiejar import CookieJar from io import IOBase -from typing import Any, Callable, Dict, List, Optional, Pattern, Type, TypeVar, Union +from typing import Any, Callable, Dict, List, Optional, Pattern, Type, TypeVar, Union, overload from requests import Response, Session from urllib3.response import HTTPResponse @@ -54,7 +54,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -77,7 +77,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -99,7 +99,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -121,7 +121,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -143,7 +143,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -165,7 +165,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -187,7 +187,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -209,7 +209,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -231,7 +231,7 @@ class MockerCore: text: Union[str, Callback[str]] = ..., content: Union[bytes, Callback[bytes]] = ..., body: Union[IOBase, Callback[IOBase]] = ..., - raw: HTTPResponse = ..., + raw: Union[HTTPResponse, Callback[HTTPResponse]] = ..., exc: Union[Exception, Type[Exception]] = ..., additional_matcher: AdditionalMatcher = ..., json_encoder: Optional[Type[JSONEncoder]] = ..., @@ -239,6 +239,7 @@ class MockerCore: ) -> _Matcher: ... _T = TypeVar('_T') +_CallableT = TypeVar("_CallableT", bound=Callable) class Mocker(MockerCore): TEST_PREFIX: str = ... @@ -246,6 +247,7 @@ class Mocker(MockerCore): def __init__( self, + *, kw: str = ..., case_sensitive: bool = ..., adapter: Any = ..., @@ -255,9 +257,12 @@ class Mocker(MockerCore): ) -> None: ... def __enter__(self) -> Any: ... def __exit__(self, type: Any, value: Any, traceback: Any) -> None: ... - def __call__(self, obj: Any) -> Any: ... + @overload + def __call__(self, obj: type[_T]) -> type[_T]: ... + @overload + def __call__(self, obj: _CallableT) -> _CallableT: ... def copy(self) -> Mocker: ... - def decorate_callable(self, func: Callable[..., _T]) -> Callable[..., _T]: ... + def decorate_callable(self, func: _CallableT) -> _CallableT: ... def decorate_class(self, klass: Type[_T]) -> Type[_T]: ... mock = Mocker diff --git a/contrib/python/requests-mock/py3/requests_mock/request.py b/contrib/python/requests-mock/py3/requests_mock/request.py index 05cbc3d4a3..8f7a367f95 100644 --- a/contrib/python/requests-mock/py3/requests_mock/request.py +++ b/contrib/python/requests-mock/py3/requests_mock/request.py @@ -12,10 +12,9 @@ import copy import json +import urllib.parse import requests -import six -from six.moves.urllib import parse as urlparse class _RequestObjectProxy(object): @@ -61,7 +60,7 @@ class _RequestObjectProxy(object): if not self._case_sensitive: url = url.lower() - self._url_parts_ = urlparse.urlparse(url) + self._url_parts_ = urllib.parse.urlparse(url) return self._url_parts_ @@ -110,7 +109,8 @@ class _RequestObjectProxy(object): @property def qs(self): if self._qs is None: - self._qs = urlparse.parse_qs(self.query, keep_blank_values=True) + self._qs = urllib.parse.parse_qs(self.query, + keep_blank_values=True) return self._qs @@ -146,7 +146,7 @@ class _RequestObjectProxy(object): def text(self): body = self.body - if isinstance(body, six.binary_type): + if isinstance(body, bytes): body = body.decode('utf-8') return body diff --git a/contrib/python/requests-mock/py3/requests_mock/response.py b/contrib/python/requests-mock/py3/requests_mock/response.py index 5855539273..92032623bc 100644 --- a/contrib/python/requests-mock/py3/requests_mock/response.py +++ b/contrib/python/requests-mock/py3/requests_mock/response.py @@ -10,17 +10,17 @@ # License for the specific language governing permissions and limitations # under the License. +import io +import http.client import json as jsonutils from requests.adapters import HTTPAdapter from requests.cookies import MockRequest, MockResponse from requests.cookies import RequestsCookieJar from requests.cookies import merge_cookies, cookiejar_from_dict -from requests.packages.urllib3.response import HTTPResponse from requests.utils import get_encoding_from_headers -import six +from urllib3.response import HTTPResponse -from requests_mock import compat from requests_mock import exceptions _BODY_ARGS = frozenset(['raw', 'body', 'content', 'text', 'json']) @@ -100,8 +100,7 @@ def _extract_cookies(request, response, cookies): """ # This will add cookies set manually via the Set-Cookie or Set-Cookie2 # header but this only allows 1 cookie to be set. - http_message = compat._FakeHTTPMessage(response.headers) - response.cookies.extract_cookies(MockResponse(http_message), + response.cookies.extract_cookies(MockResponse(response.raw.headers), MockRequest(request)) # This allows you to pass either a CookieJar or a dictionary to request_uri @@ -110,7 +109,7 @@ def _extract_cookies(request, response, cookies): merge_cookies(response.cookies, cookies) -class _IOReader(six.BytesIO): +class _IOReader(io.BytesIO): """A reader that makes a BytesIO look like a HTTPResponse. A HTTPResponse will return an empty string when you read from it after @@ -120,20 +119,19 @@ class _IOReader(six.BytesIO): def read(self, *args, **kwargs): if self.closed: - return six.b('') + return b'' # if the file is open, but you asked for zero bytes read you should get # back zero without closing the stream. if len(args) > 0 and args[0] == 0: - return six.b('') + return b'' - # not a new style object in python 2 - result = six.BytesIO.read(self, *args, **kwargs) + result = io.BytesIO.read(self, *args, **kwargs) # when using resp.iter_content(None) it'll go through a different # request path in urllib3. This path checks whether the object is # marked closed instead of the return value. see gh124. - if result == six.b(''): + if result == b'': self.close() return result @@ -172,9 +170,9 @@ def create_response(request, **kwargs): headers = kwargs.pop('headers', {}) encoding = None - if content is not None and not isinstance(content, six.binary_type): + if content is not None and not isinstance(content, bytes): raise TypeError('Content should be binary data') - if text is not None and not isinstance(text, six.string_types): + if text is not None and not isinstance(text, str): raise TypeError('Text should be string data') if json is not None: @@ -187,13 +185,12 @@ def create_response(request, **kwargs): body = _IOReader(content) if not raw: status = kwargs.get('status_code', _DEFAULT_STATUS) - reason = kwargs.get('reason', - six.moves.http_client.responses.get(status)) + reason = kwargs.get('reason', http.client.responses.get(status)) raw = HTTPResponse(status=status, reason=reason, headers=headers, - body=body or _IOReader(six.b('')), + body=body or _IOReader(b''), decode_content=False, enforce_content_length=False, preload_content=False, @@ -241,11 +238,11 @@ class _MatcherResponse(object): text = self._params.get('text') if content is not None and not (callable(content) or - isinstance(content, six.binary_type)): + isinstance(content, bytes)): raise TypeError('Content should be a callback or binary data') if text is not None and not (callable(text) or - isinstance(text, six.string_types)): + isinstance(text, str)): raise TypeError('Text should be a callback or string data') def get_response(self, request): @@ -273,7 +270,7 @@ class _MatcherResponse(object): text=_call(self._params.get('text')), content=_call(self._params.get('content')), body=_call(self._params.get('body')), - raw=self._params.get('raw'), + raw=_call(self._params.get('raw')), json_encoder=self._params.get('json_encoder'), status_code=context.status_code, reason=context.reason, diff --git a/contrib/python/requests-mock/py3/requests_mock/response.pyi b/contrib/python/requests-mock/py3/requests_mock/response.pyi index e7c8977883..fbcb535eac 100644 --- a/contrib/python/requests-mock/py3/requests_mock/response.pyi +++ b/contrib/python/requests-mock/py3/requests_mock/response.pyi @@ -1,9 +1,8 @@ # Stubs for requests_mock.response +import io from typing import Any, Dict -import six - from requests import Request, Response from requests.cookies import RequestsCookieJar @@ -14,7 +13,8 @@ class _FakeConnection: def send(self, request: Any, **kwargs: Any) -> None: ... def close(self) -> None: ... -class _IOReader(six.BytesIO): +class _IOReader(io.BytesIO): + def read(self, *args: Any, **kwargs: Any) -> Any: ... def create_response(request: Any, **kwargs: Any) -> Response: ... diff --git a/contrib/python/requests-mock/py3/ya.make b/contrib/python/requests-mock/py3/ya.make index b022b84019..d54c1b3e5a 100644 --- a/contrib/python/requests-mock/py3/ya.make +++ b/contrib/python/requests-mock/py3/ya.make @@ -2,13 +2,12 @@ PY3_LIBRARY() -VERSION(1.11.0) +VERSION(1.12.0) LICENSE(Apache-2.0) PEERDIR( contrib/python/requests - contrib/python/six ) NO_LINT() @@ -24,7 +23,6 @@ PY_SRCS( requests_mock/__init__.pyi requests_mock/adapter.py requests_mock/adapter.pyi - requests_mock/compat.py requests_mock/contrib/__init__.py requests_mock/contrib/_pytest_plugin.py requests_mock/contrib/_pytest_plugin.pyi |