Compare commits
4 Commits
1cfa74b9dd
...
3e221b77b4
Author | SHA1 | Date |
---|---|---|
Chris Chua | 3e221b77b4 | |
Vladimir Magamedov | 62f968a4c8 | |
Vladimir Magamedov | e9adb679ec | |
chua | 0dfe05769e |
|
@ -4,6 +4,9 @@ Changelog
|
|||
0.4.8
|
||||
~~~~~
|
||||
|
||||
- Fixed ``authority`` header for the case when Channel's ``host`` argument
|
||||
is the IPv6 address
|
||||
- Fixed ``Channel`` for the case when ``ssl`` module is not available
|
||||
- Dropped Python 3.7 support
|
||||
- Added "wheel" packaging format
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
from .const import Status
|
||||
from .exceptions import GRPCError
|
||||
|
||||
__version__ = '0.4.8rc1'
|
||||
__version__ = '0.4.8rc2'
|
||||
|
||||
__all__ = (
|
||||
'Status',
|
||||
|
|
|
@ -4,6 +4,7 @@ import http
|
|||
import time
|
||||
import asyncio
|
||||
import warnings
|
||||
import ipaddress
|
||||
|
||||
from types import TracebackType
|
||||
from typing import Generic, Optional, Union, Type, List, Sequence, Any, cast
|
||||
|
@ -683,9 +684,8 @@ class Channel:
|
|||
self._codec = codec
|
||||
self._status_details_codec = status_details_codec
|
||||
self._ssl = ssl or None
|
||||
self._authority = '{}:{}'.format(self._host, self._port)
|
||||
self._scheme = 'https' if self._ssl else 'http'
|
||||
self._authority = '{}:{}'.format(self._host, self._port)
|
||||
self._authority = self._get_authority(self._host, self._port)
|
||||
self._h2_config = H2Configuration(
|
||||
client_side=True,
|
||||
header_encoding='ascii',
|
||||
|
@ -779,6 +779,15 @@ class Channel:
|
|||
ctx.set_alpn_protocols(['h2'])
|
||||
return ctx
|
||||
|
||||
def _get_authority(self, host: str, port: int) -> str:
|
||||
try:
|
||||
ipv6_address = ipaddress.IPv6Address(host)
|
||||
except ipaddress.AddressValueError:
|
||||
pass
|
||||
else:
|
||||
host = f"[{ipv6_address}]"
|
||||
return "{}:{}".format(host, port)
|
||||
|
||||
def request(
|
||||
self,
|
||||
name: str,
|
||||
|
|
|
@ -22,6 +22,7 @@ _CARDINALITY = {
|
|||
(True, True): const.Cardinality.STREAM_STREAM,
|
||||
}
|
||||
|
||||
_PB2_MODULE_PREFIX_PARAMETER_KEY = 'pb2_module_prefix'
|
||||
|
||||
class Method(NamedTuple):
|
||||
name: str
|
||||
|
@ -174,8 +175,9 @@ def _base_module_name(proto_file_path: str) -> str:
|
|||
return basename.replace("-", "_").replace("/", ".")
|
||||
|
||||
|
||||
_pb2_module_prefix: str = ''
|
||||
def _proto2pb2_module_name(proto_file_path: str) -> str:
|
||||
return _base_module_name(proto_file_path) + "_pb2"
|
||||
return _pb2_module_prefix + _base_module_name(proto_file_path) + "_pb2"
|
||||
|
||||
|
||||
def _proto2grpc_module_name(proto_file_path: str) -> str:
|
||||
|
@ -208,10 +210,19 @@ def _type_names(
|
|||
parents.pop()
|
||||
|
||||
|
||||
def _populate_config(request_parameter: str):
|
||||
global _pb2_module_prefix
|
||||
config = dict(item.split("=") for item in request_parameter.split(','))
|
||||
if config.get(_PB2_MODULE_PREFIX_PARAMETER_KEY):
|
||||
_pb2_module_prefix = config[_PB2_MODULE_PREFIX_PARAMETER_KEY]
|
||||
|
||||
|
||||
def main() -> None:
|
||||
with os.fdopen(sys.stdin.fileno(), 'rb') as inp:
|
||||
request = CodeGeneratorRequest.FromString(inp.read())
|
||||
|
||||
_populate_config(request.parameter)
|
||||
|
||||
types_map: Dict[str, str] = {}
|
||||
for pf in request.proto_file:
|
||||
for mt in pf.message_type:
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import os
|
||||
import socket
|
||||
import tempfile
|
||||
import ipaddress
|
||||
|
||||
import pytest
|
||||
|
||||
|
@ -46,19 +47,27 @@ class ClientServer:
|
|||
channel = None
|
||||
channel_ctx = None
|
||||
|
||||
def __init__(self, *, host="127.0.0.1"):
|
||||
self.host = host
|
||||
|
||||
async def __aenter__(self):
|
||||
host = '127.0.0.1'
|
||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
||||
s.bind(('127.0.0.1', 0))
|
||||
_, port = s.getsockname()
|
||||
try:
|
||||
ipaddress.IPv6Address(self.host)
|
||||
except ipaddress.AddressValueError:
|
||||
family = socket.AF_INET
|
||||
else:
|
||||
family = socket.AF_INET6
|
||||
with socket.socket(family, socket.SOCK_STREAM) as s:
|
||||
s.bind((self.host, 0))
|
||||
_, port, *_ = s.getsockname()
|
||||
|
||||
dummy_service = DummyService()
|
||||
|
||||
self.server = Server([dummy_service])
|
||||
await self.server.start(host, port)
|
||||
await self.server.start(self.host, port)
|
||||
self.server_ctx = await self.server.__aenter__()
|
||||
|
||||
self.channel = Channel(host=host, port=port)
|
||||
self.channel = Channel(host=self.host, port=port)
|
||||
self.channel_ctx = await self.channel.__aenter__()
|
||||
dummy_stub = DummyServiceStub(self.channel)
|
||||
return dummy_service, dummy_stub
|
||||
|
@ -211,3 +220,12 @@ async def test_stream_stream_advanced():
|
|||
assert await stream.recv_message() == DummyReply(value='baz')
|
||||
|
||||
assert await stream.recv_message() is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.skipif(not socket.has_ipv6, reason="No IPv6 support")
|
||||
async def test_ipv6():
|
||||
async with ClientServer(host="::1") as (handler, stub):
|
||||
reply = await stub.UnaryUnary(DummyRequest(value='ping'))
|
||||
assert reply == DummyReply(value='pong')
|
||||
assert handler.log == [DummyRequest(value='ping')]
|
||||
|
|
Loading…
Reference in New Issue