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
|
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
|
- Dropped Python 3.7 support
|
||||||
- Added "wheel" packaging format
|
- Added "wheel" packaging format
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
from .const import Status
|
from .const import Status
|
||||||
from .exceptions import GRPCError
|
from .exceptions import GRPCError
|
||||||
|
|
||||||
__version__ = '0.4.8rc1'
|
__version__ = '0.4.8rc2'
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'Status',
|
'Status',
|
||||||
|
|
|
@ -4,6 +4,7 @@ import http
|
||||||
import time
|
import time
|
||||||
import asyncio
|
import asyncio
|
||||||
import warnings
|
import warnings
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
from types import TracebackType
|
from types import TracebackType
|
||||||
from typing import Generic, Optional, Union, Type, List, Sequence, Any, cast
|
from typing import Generic, Optional, Union, Type, List, Sequence, Any, cast
|
||||||
|
@ -683,9 +684,8 @@ class Channel:
|
||||||
self._codec = codec
|
self._codec = codec
|
||||||
self._status_details_codec = status_details_codec
|
self._status_details_codec = status_details_codec
|
||||||
self._ssl = ssl or None
|
self._ssl = ssl or None
|
||||||
self._authority = '{}:{}'.format(self._host, self._port)
|
|
||||||
self._scheme = 'https' if self._ssl else 'http'
|
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(
|
self._h2_config = H2Configuration(
|
||||||
client_side=True,
|
client_side=True,
|
||||||
header_encoding='ascii',
|
header_encoding='ascii',
|
||||||
|
@ -779,6 +779,15 @@ class Channel:
|
||||||
ctx.set_alpn_protocols(['h2'])
|
ctx.set_alpn_protocols(['h2'])
|
||||||
return ctx
|
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(
|
def request(
|
||||||
self,
|
self,
|
||||||
name: str,
|
name: str,
|
||||||
|
|
|
@ -22,6 +22,7 @@ _CARDINALITY = {
|
||||||
(True, True): const.Cardinality.STREAM_STREAM,
|
(True, True): const.Cardinality.STREAM_STREAM,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_PB2_MODULE_PREFIX_PARAMETER_KEY = 'pb2_module_prefix'
|
||||||
|
|
||||||
class Method(NamedTuple):
|
class Method(NamedTuple):
|
||||||
name: str
|
name: str
|
||||||
|
@ -174,8 +175,9 @@ def _base_module_name(proto_file_path: str) -> str:
|
||||||
return basename.replace("-", "_").replace("/", ".")
|
return basename.replace("-", "_").replace("/", ".")
|
||||||
|
|
||||||
|
|
||||||
|
_pb2_module_prefix: str = ''
|
||||||
def _proto2pb2_module_name(proto_file_path: str) -> 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:
|
def _proto2grpc_module_name(proto_file_path: str) -> str:
|
||||||
|
@ -208,10 +210,19 @@ def _type_names(
|
||||||
parents.pop()
|
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:
|
def main() -> None:
|
||||||
with os.fdopen(sys.stdin.fileno(), 'rb') as inp:
|
with os.fdopen(sys.stdin.fileno(), 'rb') as inp:
|
||||||
request = CodeGeneratorRequest.FromString(inp.read())
|
request = CodeGeneratorRequest.FromString(inp.read())
|
||||||
|
|
||||||
|
_populate_config(request.parameter)
|
||||||
|
|
||||||
types_map: Dict[str, str] = {}
|
types_map: Dict[str, str] = {}
|
||||||
for pf in request.proto_file:
|
for pf in request.proto_file:
|
||||||
for mt in pf.message_type:
|
for mt in pf.message_type:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import os
|
import os
|
||||||
import socket
|
import socket
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import ipaddress
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
@ -46,19 +47,27 @@ class ClientServer:
|
||||||
channel = None
|
channel = None
|
||||||
channel_ctx = None
|
channel_ctx = None
|
||||||
|
|
||||||
|
def __init__(self, *, host="127.0.0.1"):
|
||||||
|
self.host = host
|
||||||
|
|
||||||
async def __aenter__(self):
|
async def __aenter__(self):
|
||||||
host = '127.0.0.1'
|
try:
|
||||||
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
|
ipaddress.IPv6Address(self.host)
|
||||||
s.bind(('127.0.0.1', 0))
|
except ipaddress.AddressValueError:
|
||||||
_, port = s.getsockname()
|
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()
|
dummy_service = DummyService()
|
||||||
|
|
||||||
self.server = Server([dummy_service])
|
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.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__()
|
self.channel_ctx = await self.channel.__aenter__()
|
||||||
dummy_stub = DummyServiceStub(self.channel)
|
dummy_stub = DummyServiceStub(self.channel)
|
||||||
return dummy_service, dummy_stub
|
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() == DummyReply(value='baz')
|
||||||
|
|
||||||
assert await stream.recv_message() is None
|
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