diff --git a/.gitattributes b/.gitattributes index 30f37ce..4e33b33 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,2 @@ pymapadmin/grpc/admin_grpc.py -diff pymapadmin/grpc/admin_pb2.py -diff -pymapadmin/grpc/admin_pb2.pyi -diff diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 65fe5ff..18b6283 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -13,7 +13,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: [3.9] + python-version: ['3.10'] steps: - uses: actions/checkout@v2 @@ -50,7 +50,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.9' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip setuptools wheel diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 1ffe4fe..d8dfa48 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.9' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip setuptools wheel twine @@ -35,7 +35,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v2 with: - python-version: '3.9' + python-version: '3.10' - name: Install dependencies run: | python -m pip install --upgrade pip setuptools wheel diff --git a/pymapadmin/commands/base.py b/pymapadmin/commands/base.py index 6757b70..d0a07fb 100644 --- a/pymapadmin/commands/base.py +++ b/pymapadmin/commands/base.py @@ -13,7 +13,8 @@ from .. import __version__ as client_version from ..local import token_file -from ..typing import StubT, RequestT, ResponseT, MethodProtocol +from ..typing import StubT, MethodProtocol, RequestT, ResponseT, \ + AdminRequestT, AdminResponseT from ..grpc.admin_pb2 import SUCCESS try: @@ -23,7 +24,7 @@ except ImportError: # pragma: no cover pass -__all__ = ['Command', 'ClientCommand'] +__all__ = ['Command', 'ClientCommand', 'AdminCommand'] class Command(metaclass=ABCMeta): @@ -106,6 +107,7 @@ def build_request(self) -> RequestT: """Build the request.""" ... + @abstractmethod def handle_response(self, response: ResponseT, outfile: TextIO) -> int: """Handle each response. For streaming responses, this will be called once for each streamed response as long as ``0`` is returned. @@ -118,32 +120,7 @@ def handle_response(self, response: ResponseT, outfile: TextIO) -> int: outfile: The file object to print the output to. """ - if response.result.code == SUCCESS: - self.handle_success(response, outfile) - return 0 - else: - self.handle_failure(response, outfile) - return 1 - - def handle_success(self, response: ResponseT, outfile: TextIO) -> None: - """Print a successful response. - - Args: - response: The response from the server. - outfile: The file object to print the output to. - - """ - print(response, file=outfile) - - def handle_failure(self, response: ResponseT, outfile: TextIO) -> None: - """Print a failure response. - - Args: - response: The response from the server. - outfile: The file object to print the output to. - - """ - print(response.result, file=sys.stderr) + ... def handle_exception(self, exc: Exception, outfile: TextIO) -> int: """Handle an exception that occurred while calling the RPC function. @@ -170,3 +147,45 @@ async def __call__(self, outfile: TextIO) -> int: return self.handle_exception(exc, outfile) else: return 0 + + +class AdminCommand(ClientCommand[StubT, AdminRequestT, AdminResponseT], + metaclass=ABCMeta): + """Interface for client command implementations. + + Args: + args: The command line arguments. + client: The client object. + + """ + + def handle_response(self, response: AdminResponseT, + outfile: TextIO) -> int: + if response.result.code == SUCCESS: + self.handle_success(response, outfile) + return 0 + else: + self.handle_failure(response, outfile) + return 1 + + def handle_success(self, response: AdminResponseT, + outfile: TextIO) -> None: + """Print a successful response. + + Args: + response: The response from the server. + outfile: The file object to print the output to. + + """ + print(response, file=outfile) + + def handle_failure(self, response: AdminResponseT, + outfile: TextIO) -> None: + """Print a failure response. + + Args: + response: The response from the server. + outfile: The file object to print the output to. + + """ + print(response.result, file=sys.stderr) diff --git a/pymapadmin/commands/health.py b/pymapadmin/commands/health.py new file mode 100644 index 0000000..8a215a2 --- /dev/null +++ b/pymapadmin/commands/health.py @@ -0,0 +1,49 @@ + +from __future__ import annotations + +from argparse import ArgumentParser +from typing import Any, TextIO + +from grpclib.health.v1.health_grpc import HealthStub +from grpclib.health.v1.health_pb2 import \ + HealthCheckRequest, HealthCheckResponse + +from .base import ClientCommand +from ..typing import RequestT, ResponseT, MethodProtocol + +__all__ = ['CheckCommand'] + + +class HealthCommand(ClientCommand[HealthStub, RequestT, ResponseT]): + + @property + def client(self) -> HealthStub: + return HealthStub(self.channel) + + +class CheckCommand(HealthCommand[HealthCheckRequest, + HealthCheckResponse]): + """Check the health of the server.""" + + @classmethod + def add_subparser(cls, name: str, subparsers: Any) \ + -> ArgumentParser: # pragma: no cover + return subparsers.add_parser( + name, description=cls.__doc__, + help='check the server health') + + @property + def method(self) -> MethodProtocol[HealthCheckRequest, + HealthCheckResponse]: + return self.client.Check + + def build_request(self) -> HealthCheckRequest: + return HealthCheckRequest() + + def _is_serving(self, response: HealthCheckResponse) -> bool: + return response.status == HealthCheckResponse.ServingStatus.SERVING + + def handle_response(self, response: HealthCheckResponse, + outfile: TextIO) -> int: + print(response, file=outfile) + return 0 if self._is_serving(response) else 1 diff --git a/pymapadmin/commands/mailbox.py b/pymapadmin/commands/mailbox.py index dce0a5f..0ced6ae 100644 --- a/pymapadmin/commands/mailbox.py +++ b/pymapadmin/commands/mailbox.py @@ -6,15 +6,15 @@ from argparse import ArgumentParser, FileType from typing import Any, TextIO -from .base import ClientCommand -from ..typing import RequestT, ResponseT, MethodProtocol +from .base import AdminCommand +from ..typing import AdminRequestT, AdminResponseT, MethodProtocol from ..grpc.admin_grpc import MailboxStub from ..grpc.admin_pb2 import AppendRequest, AppendResponse __all__ = ['AppendCommand'] -class MailboxCommand(ClientCommand[MailboxStub, RequestT, ResponseT]): +class MailboxCommand(AdminCommand[MailboxStub, AdminRequestT, AdminResponseT]): @property def client(self) -> MailboxStub: diff --git a/pymapadmin/commands/system.py b/pymapadmin/commands/system.py index 2e69b52..8d08879 100644 --- a/pymapadmin/commands/system.py +++ b/pymapadmin/commands/system.py @@ -6,10 +6,10 @@ from contextlib import closing from typing import Any, Optional, TextIO -from .base import Command, ClientCommand +from .base import Command, AdminCommand from ..config import Config from ..local import config_file, token_file -from ..typing import RequestT, ResponseT, MethodProtocol +from ..typing import AdminRequestT, AdminResponseT, MethodProtocol from ..grpc.admin_grpc import SystemStub from ..grpc.admin_pb2 import LoginRequest, LoginResponse, \ PingRequest, PingResponse @@ -17,7 +17,7 @@ __all__ = ['SaveArgsCommand', 'LoginCommand', 'PingCommand'] -class SystemCommand(ClientCommand[SystemStub, RequestT, ResponseT]): +class SystemCommand(AdminCommand[SystemStub, AdminRequestT, AdminResponseT]): @property def client(self) -> SystemStub: diff --git a/pymapadmin/commands/user.py b/pymapadmin/commands/user.py index cb41caa..18fa65d 100644 --- a/pymapadmin/commands/user.py +++ b/pymapadmin/commands/user.py @@ -6,8 +6,8 @@ from collections.abc import Mapping, Sequence from typing import Any, Optional -from .base import ClientCommand -from ..typing import RequestT, ResponseT, MethodProtocol +from .base import AdminCommand +from ..typing import AdminRequestT, AdminResponseT, MethodProtocol from ..grpc.admin_grpc import UserStub from ..grpc.admin_pb2 import \ UserData, UserResponse, GetUserRequest, SetUserRequest, DeleteUserRequest @@ -15,7 +15,7 @@ __all__ = ['GetUserCommand', 'SetUserCommand', 'DeleteUserCommand'] -class UserCommand(ClientCommand[UserStub, RequestT, ResponseT]): +class UserCommand(AdminCommand[UserStub, AdminRequestT, AdminResponseT]): @property def client(self) -> UserStub: diff --git a/pymapadmin/grpc/admin.proto b/pymapadmin/grpc/admin.proto index faa7c35..92301e4 100644 --- a/pymapadmin/grpc/admin.proto +++ b/pymapadmin/grpc/admin.proto @@ -16,13 +16,13 @@ message Result { message LoginRequest { string authcid = 1; string secret = 2; - oneof optional_authzid { string authzid = 3; } - oneof optional_token_expiration { double token_expiration = 4; } + optional string authzid = 3; + optional double token_expiration = 4; } message LoginResponse { Result result = 1; - oneof optional_bearer_token { string bearer_token = 2; } + optional string bearer_token = 2; } message PingRequest {} @@ -35,9 +35,9 @@ message PingResponse { message AppendRequest { string user = 1; - oneof optional_sender { string sender = 2; } - oneof optional_recipient { string recipient = 3; } - oneof optional_mailbox { string mailbox = 4; } + optional string sender = 2; + optional string recipient = 3; + optional string mailbox = 4; bytes data = 5; repeated string flags = 6; uint64 when = 7; @@ -46,12 +46,12 @@ message AppendRequest { message AppendResponse { Result result = 1; string mailbox = 2; - uint32 validity = 3; - uint32 uid = 4; + optional uint32 validity = 3; + optional uint32 uid = 4; } message UserData { - oneof optional_password { string password = 1; } + optional string password = 1; map params = 2; } @@ -70,8 +70,8 @@ message DeleteUserRequest { message UserResponse { Result result = 1; - string username = 2; - oneof optional_data { UserData data = 3; } + optional string username = 2; + UserData data = 3; } service System { diff --git a/pymapadmin/grpc/admin_pb2.py b/pymapadmin/grpc/admin_pb2.py index 21f595a..0aedfa1 100644 --- a/pymapadmin/grpc/admin_pb2.py +++ b/pymapadmin/grpc/admin_pb2.py @@ -20,7 +20,7 @@ syntax='proto3', serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x1bpymapadmin/grpc/admin.proto\x12\x0fpymapadmin.grpc\"R\n\x06Result\x12)\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1b.pymapadmin.grpc.ResultCode\x12\x10\n\x08response\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\t\"\x8f\x01\n\x0cLoginRequest\x12\x0f\n\x07\x61uthcid\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x11\n\x07\x61uthzid\x18\x03 \x01(\tH\x00\x12\x1a\n\x10token_expiration\x18\x04 \x01(\x01H\x01\x42\x12\n\x10optional_authzidB\x1b\n\x19optional_token_expiration\"i\n\rLoginResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x16\n\x0c\x62\x65\x61rer_token\x18\x02 \x01(\tH\x00\x42\x17\n\x15optional_bearer_token\"\r\n\x0bPingRequest\"k\n\x0cPingResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x15\n\rpymap_version\x18\x02 \x01(\t\x12\x1b\n\x13pymap_admin_version\x18\x03 \x01(\t\"\xbf\x01\n\rAppendRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x10\n\x06sender\x18\x02 \x01(\tH\x00\x12\x13\n\trecipient\x18\x03 \x01(\tH\x01\x12\x11\n\x07mailbox\x18\x04 \x01(\tH\x02\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\r\n\x05\x66lags\x18\x06 \x03(\t\x12\x0c\n\x04when\x18\x07 \x01(\x04\x42\x11\n\x0foptional_senderB\x14\n\x12optional_recipientB\x12\n\x10optional_mailbox\"i\n\x0e\x41ppendResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x0f\n\x07mailbox\x18\x02 \x01(\t\x12\x10\n\x08validity\x18\x03 \x01(\r\x12\x0b\n\x03uid\x18\x04 \x01(\r\"\x99\x01\n\x08UserData\x12\x12\n\x08password\x18\x01 \x01(\tH\x00\x12\x35\n\x06params\x18\x02 \x03(\x0b\x32%.pymapadmin.grpc.UserData.ParamsEntry\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x13\n\x11optional_password\"\x1e\n\x0eGetUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\"G\n\x0eSetUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.pymapadmin.grpc.UserData\"!\n\x11\x44\x65leteUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\"\x85\x01\n\x0cUserResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x10\n\x08username\x18\x02 \x01(\t\x12)\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x19.pymapadmin.grpc.UserDataH\x00\x42\x0f\n\roptional_data*&\n\nResultCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0b\n\x07\x46\x41ILURE\x10\x01\x32\x99\x01\n\x06System\x12\x45\n\x04Ping\x12\x1c.pymapadmin.grpc.PingRequest\x1a\x1d.pymapadmin.grpc.PingResponse\"\x00\x12H\n\x05Login\x12\x1d.pymapadmin.grpc.LoginRequest\x1a\x1e.pymapadmin.grpc.LoginResponse\"\x00\x32V\n\x07Mailbox\x12K\n\x06\x41ppend\x12\x1e.pymapadmin.grpc.AppendRequest\x1a\x1f.pymapadmin.grpc.AppendResponse\"\x00\x32\xf3\x01\n\x04User\x12K\n\x07GetUser\x12\x1f.pymapadmin.grpc.GetUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x12K\n\x07SetUser\x12\x1f.pymapadmin.grpc.SetUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x12Q\n\nDeleteUser\x12\".pymapadmin.grpc.DeleteUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x62\x06proto3' + serialized_pb=b'\n\x1bpymapadmin/grpc/admin.proto\x12\x0fpymapadmin.grpc\"R\n\x06Result\x12)\n\x04\x63ode\x18\x01 \x01(\x0e\x32\x1b.pymapadmin.grpc.ResultCode\x12\x10\n\x08response\x18\x02 \x01(\x0c\x12\x0b\n\x03key\x18\x03 \x01(\t\"\x85\x01\n\x0cLoginRequest\x12\x0f\n\x07\x61uthcid\x18\x01 \x01(\t\x12\x0e\n\x06secret\x18\x02 \x01(\t\x12\x14\n\x07\x61uthzid\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x1d\n\x10token_expiration\x18\x04 \x01(\x01H\x01\x88\x01\x01\x42\n\n\x08_authzidB\x13\n\x11_token_expiration\"d\n\rLoginResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x19\n\x0c\x62\x65\x61rer_token\x18\x02 \x01(\tH\x00\x88\x01\x01\x42\x0f\n\r_bearer_token\"\r\n\x0bPingRequest\"k\n\x0cPingResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x15\n\rpymap_version\x18\x02 \x01(\t\x12\x1b\n\x13pymap_admin_version\x18\x03 \x01(\t\"\xb0\x01\n\rAppendRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\x13\n\x06sender\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x16\n\trecipient\x18\x03 \x01(\tH\x01\x88\x01\x01\x12\x14\n\x07mailbox\x18\x04 \x01(\tH\x02\x88\x01\x01\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\x12\r\n\x05\x66lags\x18\x06 \x03(\t\x12\x0c\n\x04when\x18\x07 \x01(\x04\x42\t\n\x07_senderB\x0c\n\n_recipientB\n\n\x08_mailbox\"\x88\x01\n\x0e\x41ppendResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x0f\n\x07mailbox\x18\x02 \x01(\t\x12\x15\n\x08validity\x18\x03 \x01(\rH\x00\x88\x01\x01\x12\x10\n\x03uid\x18\x04 \x01(\rH\x01\x88\x01\x01\x42\x0b\n\t_validityB\x06\n\x04_uid\"\x94\x01\n\x08UserData\x12\x15\n\x08password\x18\x01 \x01(\tH\x00\x88\x01\x01\x12\x35\n\x06params\x18\x02 \x03(\x0b\x32%.pymapadmin.grpc.UserData.ParamsEntry\x1a-\n\x0bParamsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x42\x0b\n\t_password\"\x1e\n\x0eGetUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\"G\n\x0eSetUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\x12\'\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x19.pymapadmin.grpc.UserData\"!\n\x11\x44\x65leteUserRequest\x12\x0c\n\x04user\x18\x01 \x01(\t\"\x84\x01\n\x0cUserResponse\x12\'\n\x06result\x18\x01 \x01(\x0b\x32\x17.pymapadmin.grpc.Result\x12\x15\n\x08username\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\'\n\x04\x64\x61ta\x18\x03 \x01(\x0b\x32\x19.pymapadmin.grpc.UserDataB\x0b\n\t_username*&\n\nResultCode\x12\x0b\n\x07SUCCESS\x10\x00\x12\x0b\n\x07\x46\x41ILURE\x10\x01\x32\x99\x01\n\x06System\x12\x45\n\x04Ping\x12\x1c.pymapadmin.grpc.PingRequest\x1a\x1d.pymapadmin.grpc.PingResponse\"\x00\x12H\n\x05Login\x12\x1d.pymapadmin.grpc.LoginRequest\x1a\x1e.pymapadmin.grpc.LoginResponse\"\x00\x32V\n\x07Mailbox\x12K\n\x06\x41ppend\x12\x1e.pymapadmin.grpc.AppendRequest\x1a\x1f.pymapadmin.grpc.AppendResponse\"\x00\x32\xf3\x01\n\x04User\x12K\n\x07GetUser\x12\x1f.pymapadmin.grpc.GetUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x12K\n\x07SetUser\x12\x1f.pymapadmin.grpc.SetUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x12Q\n\nDeleteUser\x12\".pymapadmin.grpc.DeleteUserRequest\x1a\x1d.pymapadmin.grpc.UserResponse\"\x00\x62\x06proto3' ) _RESULTCODE = _descriptor.EnumDescriptor( @@ -43,8 +43,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1242, - serialized_end=1280, + serialized_start=1238, + serialized_end=1276, ) _sym_db.RegisterEnumDescriptor(_RESULTCODE) @@ -148,18 +148,18 @@ extension_ranges=[], oneofs=[ _descriptor.OneofDescriptor( - name='optional_authzid', full_name='pymapadmin.grpc.LoginRequest.optional_authzid', + name='_authzid', full_name='pymapadmin.grpc.LoginRequest._authzid', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), _descriptor.OneofDescriptor( - name='optional_token_expiration', full_name='pymapadmin.grpc.LoginRequest.optional_token_expiration', + name='_token_expiration', full_name='pymapadmin.grpc.LoginRequest._token_expiration', index=1, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), ], serialized_start=133, - serialized_end=276, + serialized_end=266, ) @@ -197,13 +197,13 @@ extension_ranges=[], oneofs=[ _descriptor.OneofDescriptor( - name='optional_bearer_token', full_name='pymapadmin.grpc.LoginResponse.optional_bearer_token', + name='_bearer_token', full_name='pymapadmin.grpc.LoginResponse._bearer_token', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=278, - serialized_end=383, + serialized_start=268, + serialized_end=368, ) @@ -227,8 +227,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=385, - serialized_end=398, + serialized_start=370, + serialized_end=383, ) @@ -273,8 +273,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=400, - serialized_end=507, + serialized_start=385, + serialized_end=492, ) @@ -347,23 +347,23 @@ extension_ranges=[], oneofs=[ _descriptor.OneofDescriptor( - name='optional_sender', full_name='pymapadmin.grpc.AppendRequest.optional_sender', + name='_sender', full_name='pymapadmin.grpc.AppendRequest._sender', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), _descriptor.OneofDescriptor( - name='optional_recipient', full_name='pymapadmin.grpc.AppendRequest.optional_recipient', + name='_recipient', full_name='pymapadmin.grpc.AppendRequest._recipient', index=1, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), _descriptor.OneofDescriptor( - name='optional_mailbox', full_name='pymapadmin.grpc.AppendRequest.optional_mailbox', + name='_mailbox', full_name='pymapadmin.grpc.AppendRequest._mailbox', index=2, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=510, - serialized_end=701, + serialized_start=495, + serialized_end=671, ) @@ -414,9 +414,19 @@ syntax='proto3', extension_ranges=[], oneofs=[ + _descriptor.OneofDescriptor( + name='_validity', full_name='pymapadmin.grpc.AppendResponse._validity', + index=0, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), + _descriptor.OneofDescriptor( + name='_uid', full_name='pymapadmin.grpc.AppendResponse._uid', + index=1, containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[]), ], - serialized_start=703, - serialized_end=808, + serialized_start=674, + serialized_end=810, ) @@ -454,8 +464,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=898, - serialized_end=943, + serialized_start=903, + serialized_end=948, ) _USERDATA = _descriptor.Descriptor( @@ -492,13 +502,13 @@ extension_ranges=[], oneofs=[ _descriptor.OneofDescriptor( - name='optional_password', full_name='pymapadmin.grpc.UserData.optional_password', + name='_password', full_name='pymapadmin.grpc.UserData._password', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=811, - serialized_end=964, + serialized_start=813, + serialized_end=961, ) @@ -529,8 +539,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=966, - serialized_end=996, + serialized_start=963, + serialized_end=993, ) @@ -568,8 +578,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=998, - serialized_end=1069, + serialized_start=995, + serialized_end=1066, ) @@ -600,8 +610,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1071, - serialized_end=1104, + serialized_start=1068, + serialized_end=1101, ) @@ -646,48 +656,54 @@ extension_ranges=[], oneofs=[ _descriptor.OneofDescriptor( - name='optional_data', full_name='pymapadmin.grpc.UserResponse.optional_data', + name='_username', full_name='pymapadmin.grpc.UserResponse._username', index=0, containing_type=None, create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=1107, - serialized_end=1240, + serialized_start=1104, + serialized_end=1236, ) _RESULT.fields_by_name['code'].enum_type = _RESULTCODE -_LOGINREQUEST.oneofs_by_name['optional_authzid'].fields.append( +_LOGINREQUEST.oneofs_by_name['_authzid'].fields.append( _LOGINREQUEST.fields_by_name['authzid']) -_LOGINREQUEST.fields_by_name['authzid'].containing_oneof = _LOGINREQUEST.oneofs_by_name['optional_authzid'] -_LOGINREQUEST.oneofs_by_name['optional_token_expiration'].fields.append( +_LOGINREQUEST.fields_by_name['authzid'].containing_oneof = _LOGINREQUEST.oneofs_by_name['_authzid'] +_LOGINREQUEST.oneofs_by_name['_token_expiration'].fields.append( _LOGINREQUEST.fields_by_name['token_expiration']) -_LOGINREQUEST.fields_by_name['token_expiration'].containing_oneof = _LOGINREQUEST.oneofs_by_name['optional_token_expiration'] +_LOGINREQUEST.fields_by_name['token_expiration'].containing_oneof = _LOGINREQUEST.oneofs_by_name['_token_expiration'] _LOGINRESPONSE.fields_by_name['result'].message_type = _RESULT -_LOGINRESPONSE.oneofs_by_name['optional_bearer_token'].fields.append( +_LOGINRESPONSE.oneofs_by_name['_bearer_token'].fields.append( _LOGINRESPONSE.fields_by_name['bearer_token']) -_LOGINRESPONSE.fields_by_name['bearer_token'].containing_oneof = _LOGINRESPONSE.oneofs_by_name['optional_bearer_token'] +_LOGINRESPONSE.fields_by_name['bearer_token'].containing_oneof = _LOGINRESPONSE.oneofs_by_name['_bearer_token'] _PINGRESPONSE.fields_by_name['result'].message_type = _RESULT -_APPENDREQUEST.oneofs_by_name['optional_sender'].fields.append( +_APPENDREQUEST.oneofs_by_name['_sender'].fields.append( _APPENDREQUEST.fields_by_name['sender']) -_APPENDREQUEST.fields_by_name['sender'].containing_oneof = _APPENDREQUEST.oneofs_by_name['optional_sender'] -_APPENDREQUEST.oneofs_by_name['optional_recipient'].fields.append( +_APPENDREQUEST.fields_by_name['sender'].containing_oneof = _APPENDREQUEST.oneofs_by_name['_sender'] +_APPENDREQUEST.oneofs_by_name['_recipient'].fields.append( _APPENDREQUEST.fields_by_name['recipient']) -_APPENDREQUEST.fields_by_name['recipient'].containing_oneof = _APPENDREQUEST.oneofs_by_name['optional_recipient'] -_APPENDREQUEST.oneofs_by_name['optional_mailbox'].fields.append( +_APPENDREQUEST.fields_by_name['recipient'].containing_oneof = _APPENDREQUEST.oneofs_by_name['_recipient'] +_APPENDREQUEST.oneofs_by_name['_mailbox'].fields.append( _APPENDREQUEST.fields_by_name['mailbox']) -_APPENDREQUEST.fields_by_name['mailbox'].containing_oneof = _APPENDREQUEST.oneofs_by_name['optional_mailbox'] +_APPENDREQUEST.fields_by_name['mailbox'].containing_oneof = _APPENDREQUEST.oneofs_by_name['_mailbox'] _APPENDRESPONSE.fields_by_name['result'].message_type = _RESULT +_APPENDRESPONSE.oneofs_by_name['_validity'].fields.append( + _APPENDRESPONSE.fields_by_name['validity']) +_APPENDRESPONSE.fields_by_name['validity'].containing_oneof = _APPENDRESPONSE.oneofs_by_name['_validity'] +_APPENDRESPONSE.oneofs_by_name['_uid'].fields.append( + _APPENDRESPONSE.fields_by_name['uid']) +_APPENDRESPONSE.fields_by_name['uid'].containing_oneof = _APPENDRESPONSE.oneofs_by_name['_uid'] _USERDATA_PARAMSENTRY.containing_type = _USERDATA _USERDATA.fields_by_name['params'].message_type = _USERDATA_PARAMSENTRY -_USERDATA.oneofs_by_name['optional_password'].fields.append( +_USERDATA.oneofs_by_name['_password'].fields.append( _USERDATA.fields_by_name['password']) -_USERDATA.fields_by_name['password'].containing_oneof = _USERDATA.oneofs_by_name['optional_password'] +_USERDATA.fields_by_name['password'].containing_oneof = _USERDATA.oneofs_by_name['_password'] _SETUSERREQUEST.fields_by_name['data'].message_type = _USERDATA _USERRESPONSE.fields_by_name['result'].message_type = _RESULT _USERRESPONSE.fields_by_name['data'].message_type = _USERDATA -_USERRESPONSE.oneofs_by_name['optional_data'].fields.append( - _USERRESPONSE.fields_by_name['data']) -_USERRESPONSE.fields_by_name['data'].containing_oneof = _USERRESPONSE.oneofs_by_name['optional_data'] +_USERRESPONSE.oneofs_by_name['_username'].fields.append( + _USERRESPONSE.fields_by_name['username']) +_USERRESPONSE.fields_by_name['username'].containing_oneof = _USERRESPONSE.oneofs_by_name['_username'] DESCRIPTOR.message_types_by_name['Result'] = _RESULT DESCRIPTOR.message_types_by_name['LoginRequest'] = _LOGINREQUEST DESCRIPTOR.message_types_by_name['LoginResponse'] = _LOGINRESPONSE @@ -805,8 +821,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=1283, - serialized_end=1436, + serialized_start=1279, + serialized_end=1432, methods=[ _descriptor.MethodDescriptor( name='Ping', @@ -841,8 +857,8 @@ index=1, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=1438, - serialized_end=1524, + serialized_start=1434, + serialized_end=1520, methods=[ _descriptor.MethodDescriptor( name='Append', @@ -867,8 +883,8 @@ index=2, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=1527, - serialized_end=1770, + serialized_start=1523, + serialized_end=1766, methods=[ _descriptor.MethodDescriptor( name='GetUser', diff --git a/pymapadmin/grpc/admin_pb2.pyi b/pymapadmin/grpc/admin_pb2.pyi index 96b05ca..8634227 100644 --- a/pymapadmin/grpc/admin_pb2.pyi +++ b/pymapadmin/grpc/admin_pb2.pyi @@ -12,32 +12,36 @@ import typing_extensions DESCRIPTOR: google.protobuf.descriptor.FileDescriptor = ... -global___ResultCode = ResultCode -class _ResultCode(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[ResultCode.V], builtins.type): +class _ResultCode: + ValueType = typing.NewType('ValueType', builtins.int) + V = typing.Union[ValueType] +class _ResultCodeEnumTypeWrapper(google.protobuf.internal.enum_type_wrapper._EnumTypeWrapper[_ResultCode.ValueType], builtins.type): DESCRIPTOR: google.protobuf.descriptor.EnumDescriptor = ... - SUCCESS = ResultCode.V(0) - FAILURE = ResultCode.V(1) -class ResultCode(metaclass=_ResultCode): - V = typing.NewType('V', builtins.int) -SUCCESS = ResultCode.V(0) -FAILURE = ResultCode.V(1) + SUCCESS: ResultCode.ValueType = ... # 0 + FAILURE: ResultCode.ValueType = ... # 1 +class ResultCode(_ResultCode, metaclass=_ResultCodeEnumTypeWrapper): + pass + +SUCCESS: ResultCode.ValueType = ... # 0 +FAILURE: ResultCode.ValueType = ... # 1 +global___ResultCode = ResultCode + class Result(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor = ... CODE_FIELD_NUMBER: builtins.int RESPONSE_FIELD_NUMBER: builtins.int KEY_FIELD_NUMBER: builtins.int - code: global___ResultCode.V = ... + code: global___ResultCode.ValueType = ... response: builtins.bytes = ... key: typing.Text = ... - def __init__(self, *, - code : global___ResultCode.V = ..., + code : global___ResultCode.ValueType = ..., response : builtins.bytes = ..., key : typing.Text = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal[u"code",b"code",u"key",b"key",u"response",b"response"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["code",b"code","key",b"key","response",b"response"]) -> None: ... global___Result = Result class LoginRequest(google.protobuf.message.Message): @@ -50,44 +54,40 @@ class LoginRequest(google.protobuf.message.Message): secret: typing.Text = ... authzid: typing.Text = ... token_expiration: builtins.float = ... - def __init__(self, *, authcid : typing.Text = ..., secret : typing.Text = ..., - authzid : typing.Text = ..., - token_expiration : builtins.float = ..., + authzid : typing.Optional[typing.Text] = ..., + token_expiration : typing.Optional[builtins.float] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"authzid",b"authzid",u"optional_authzid",b"optional_authzid",u"optional_token_expiration",b"optional_token_expiration",u"token_expiration",b"token_expiration"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"authcid",b"authcid",u"authzid",b"authzid",u"optional_authzid",b"optional_authzid",u"optional_token_expiration",b"optional_token_expiration",u"secret",b"secret",u"token_expiration",b"token_expiration"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_authzid",b"_authzid","_token_expiration",b"_token_expiration","authzid",b"authzid","token_expiration",b"token_expiration"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_authzid",b"_authzid","_token_expiration",b"_token_expiration","authcid",b"authcid","authzid",b"authzid","secret",b"secret","token_expiration",b"token_expiration"]) -> None: ... @typing.overload - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_authzid",b"optional_authzid"]) -> typing_extensions.Literal["authzid"]: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_authzid",b"_authzid"]) -> typing.Optional[typing_extensions.Literal["authzid"]]: ... @typing.overload - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_token_expiration",b"optional_token_expiration"]) -> typing_extensions.Literal["token_expiration"]: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_token_expiration",b"_token_expiration"]) -> typing.Optional[typing_extensions.Literal["token_expiration"]]: ... global___LoginRequest = LoginRequest class LoginResponse(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor = ... RESULT_FIELD_NUMBER: builtins.int BEARER_TOKEN_FIELD_NUMBER: builtins.int - bearer_token: typing.Text = ... - @property def result(self) -> global___Result: ... - + bearer_token: typing.Text = ... def __init__(self, *, result : typing.Optional[global___Result] = ..., - bearer_token : typing.Text = ..., + bearer_token : typing.Optional[typing.Text] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"bearer_token",b"bearer_token",u"optional_bearer_token",b"optional_bearer_token",u"result",b"result"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"bearer_token",b"bearer_token",u"optional_bearer_token",b"optional_bearer_token",u"result",b"result"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_bearer_token",b"optional_bearer_token"]) -> typing_extensions.Literal["bearer_token"]: ... + def HasField(self, field_name: typing_extensions.Literal["_bearer_token",b"_bearer_token","bearer_token",b"bearer_token","result",b"result"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_bearer_token",b"_bearer_token","bearer_token",b"bearer_token","result",b"result"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_bearer_token",b"_bearer_token"]) -> typing.Optional[typing_extensions.Literal["bearer_token"]]: ... global___LoginResponse = LoginResponse class PingRequest(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor = ... - def __init__(self, ) -> None: ... global___PingRequest = PingRequest @@ -97,20 +97,18 @@ class PingResponse(google.protobuf.message.Message): RESULT_FIELD_NUMBER: builtins.int PYMAP_VERSION_FIELD_NUMBER: builtins.int PYMAP_ADMIN_VERSION_FIELD_NUMBER: builtins.int - pymap_version: typing.Text = ... - pymap_admin_version: typing.Text = ... - @property def result(self) -> global___Result: ... - + pymap_version: typing.Text = ... + pymap_admin_version: typing.Text = ... def __init__(self, *, result : typing.Optional[global___Result] = ..., pymap_version : typing.Text = ..., pymap_admin_version : typing.Text = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"result",b"result"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"pymap_admin_version",b"pymap_admin_version",u"pymap_version",b"pymap_version",u"result",b"result"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["result",b"result"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["pymap_admin_version",b"pymap_admin_version","pymap_version",b"pymap_version","result",b"result"]) -> None: ... global___PingResponse = PingResponse class AppendRequest(google.protobuf.message.Message): @@ -127,27 +125,27 @@ class AppendRequest(google.protobuf.message.Message): recipient: typing.Text = ... mailbox: typing.Text = ... data: builtins.bytes = ... - flags: google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text] = ... + @property + def flags(self) -> google.protobuf.internal.containers.RepeatedScalarFieldContainer[typing.Text]: ... when: builtins.int = ... - def __init__(self, *, user : typing.Text = ..., - sender : typing.Text = ..., - recipient : typing.Text = ..., - mailbox : typing.Text = ..., + sender : typing.Optional[typing.Text] = ..., + recipient : typing.Optional[typing.Text] = ..., + mailbox : typing.Optional[typing.Text] = ..., data : builtins.bytes = ..., flags : typing.Optional[typing.Iterable[typing.Text]] = ..., when : builtins.int = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"mailbox",b"mailbox",u"optional_mailbox",b"optional_mailbox",u"optional_recipient",b"optional_recipient",u"optional_sender",b"optional_sender",u"recipient",b"recipient",u"sender",b"sender"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"data",b"data",u"flags",b"flags",u"mailbox",b"mailbox",u"optional_mailbox",b"optional_mailbox",u"optional_recipient",b"optional_recipient",u"optional_sender",b"optional_sender",u"recipient",b"recipient",u"sender",b"sender",u"user",b"user",u"when",b"when"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_mailbox",b"_mailbox","_recipient",b"_recipient","_sender",b"_sender","mailbox",b"mailbox","recipient",b"recipient","sender",b"sender"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_mailbox",b"_mailbox","_recipient",b"_recipient","_sender",b"_sender","data",b"data","flags",b"flags","mailbox",b"mailbox","recipient",b"recipient","sender",b"sender","user",b"user","when",b"when"]) -> None: ... @typing.overload - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_mailbox",b"optional_mailbox"]) -> typing_extensions.Literal["mailbox"]: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_mailbox",b"_mailbox"]) -> typing.Optional[typing_extensions.Literal["mailbox"]]: ... @typing.overload - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_recipient",b"optional_recipient"]) -> typing_extensions.Literal["recipient"]: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_recipient",b"_recipient"]) -> typing.Optional[typing_extensions.Literal["recipient"]]: ... @typing.overload - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_sender",b"optional_sender"]) -> typing_extensions.Literal["sender"]: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_sender",b"_sender"]) -> typing.Optional[typing_extensions.Literal["sender"]]: ... global___AppendRequest = AppendRequest class AppendResponse(google.protobuf.message.Message): @@ -156,22 +154,24 @@ class AppendResponse(google.protobuf.message.Message): MAILBOX_FIELD_NUMBER: builtins.int VALIDITY_FIELD_NUMBER: builtins.int UID_FIELD_NUMBER: builtins.int + @property + def result(self) -> global___Result: ... mailbox: typing.Text = ... validity: builtins.int = ... uid: builtins.int = ... - - @property - def result(self) -> global___Result: ... - def __init__(self, *, result : typing.Optional[global___Result] = ..., mailbox : typing.Text = ..., - validity : builtins.int = ..., - uid : builtins.int = ..., + validity : typing.Optional[builtins.int] = ..., + uid : typing.Optional[builtins.int] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"result",b"result"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"mailbox",b"mailbox",u"result",b"result",u"uid",b"uid",u"validity",b"validity"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["_uid",b"_uid","_validity",b"_validity","result",b"result","uid",b"uid","validity",b"validity"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_uid",b"_uid","_validity",b"_validity","mailbox",b"mailbox","result",b"result","uid",b"uid","validity",b"validity"]) -> None: ... + @typing.overload + def WhichOneof(self, oneof_group: typing_extensions.Literal["_uid",b"_uid"]) -> typing.Optional[typing_extensions.Literal["uid"]]: ... + @typing.overload + def WhichOneof(self, oneof_group: typing_extensions.Literal["_validity",b"_validity"]) -> typing.Optional[typing_extensions.Literal["validity"]]: ... global___AppendResponse = AppendResponse class UserData(google.protobuf.message.Message): @@ -182,41 +182,37 @@ class UserData(google.protobuf.message.Message): VALUE_FIELD_NUMBER: builtins.int key: typing.Text = ... value: typing.Text = ... - def __init__(self, *, key : typing.Text = ..., value : typing.Text = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal[u"key",b"key",u"value",b"value"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["key",b"key","value",b"value"]) -> None: ... PASSWORD_FIELD_NUMBER: builtins.int PARAMS_FIELD_NUMBER: builtins.int password: typing.Text = ... - @property def params(self) -> google.protobuf.internal.containers.ScalarMap[typing.Text, typing.Text]: ... - def __init__(self, *, - password : typing.Text = ..., + password : typing.Optional[typing.Text] = ..., params : typing.Optional[typing.Mapping[typing.Text, typing.Text]] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"optional_password",b"optional_password",u"password",b"password"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"optional_password",b"optional_password",u"params",b"params",u"password",b"password"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_password",b"optional_password"]) -> typing_extensions.Literal["password"]: ... + def HasField(self, field_name: typing_extensions.Literal["_password",b"_password","password",b"password"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_password",b"_password","params",b"params","password",b"password"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_password",b"_password"]) -> typing.Optional[typing_extensions.Literal["password"]]: ... global___UserData = UserData class GetUserRequest(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor = ... USER_FIELD_NUMBER: builtins.int user: typing.Text = ... - def __init__(self, *, user : typing.Text = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal[u"user",b"user"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["user",b"user"]) -> None: ... global___GetUserRequest = GetUserRequest class SetUserRequest(google.protobuf.message.Message): @@ -224,29 +220,26 @@ class SetUserRequest(google.protobuf.message.Message): USER_FIELD_NUMBER: builtins.int DATA_FIELD_NUMBER: builtins.int user: typing.Text = ... - @property def data(self) -> global___UserData: ... - def __init__(self, *, user : typing.Text = ..., data : typing.Optional[global___UserData] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"data",b"data"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"data",b"data",u"user",b"user"]) -> None: ... + def HasField(self, field_name: typing_extensions.Literal["data",b"data"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["data",b"data","user",b"user"]) -> None: ... global___SetUserRequest = SetUserRequest class DeleteUserRequest(google.protobuf.message.Message): DESCRIPTOR: google.protobuf.descriptor.Descriptor = ... USER_FIELD_NUMBER: builtins.int user: typing.Text = ... - def __init__(self, *, user : typing.Text = ..., ) -> None: ... - def ClearField(self, field_name: typing_extensions.Literal[u"user",b"user"]) -> None: ... + def ClearField(self, field_name: typing_extensions.Literal["user",b"user"]) -> None: ... global___DeleteUserRequest = DeleteUserRequest class UserResponse(google.protobuf.message.Message): @@ -254,21 +247,18 @@ class UserResponse(google.protobuf.message.Message): RESULT_FIELD_NUMBER: builtins.int USERNAME_FIELD_NUMBER: builtins.int DATA_FIELD_NUMBER: builtins.int - username: typing.Text = ... - @property def result(self) -> global___Result: ... - + username: typing.Text = ... @property def data(self) -> global___UserData: ... - def __init__(self, *, result : typing.Optional[global___Result] = ..., - username : typing.Text = ..., + username : typing.Optional[typing.Text] = ..., data : typing.Optional[global___UserData] = ..., ) -> None: ... - def HasField(self, field_name: typing_extensions.Literal[u"data",b"data",u"optional_data",b"optional_data",u"result",b"result"]) -> builtins.bool: ... - def ClearField(self, field_name: typing_extensions.Literal[u"data",b"data",u"optional_data",b"optional_data",u"result",b"result",u"username",b"username"]) -> None: ... - def WhichOneof(self, oneof_group: typing_extensions.Literal[u"optional_data",b"optional_data"]) -> typing_extensions.Literal["data"]: ... + def HasField(self, field_name: typing_extensions.Literal["_username",b"_username","data",b"data","result",b"result","username",b"username"]) -> builtins.bool: ... + def ClearField(self, field_name: typing_extensions.Literal["_username",b"_username","data",b"data","result",b"result","username",b"username"]) -> None: ... + def WhichOneof(self, oneof_group: typing_extensions.Literal["_username",b"_username"]) -> typing.Optional[typing_extensions.Literal["username"]]: ... global___UserResponse = UserResponse diff --git a/pymapadmin/grpc/grpc_tools.protoc-args b/pymapadmin/grpc/grpc_tools.protoc-args index 398111e..aa94d3d 100644 --- a/pymapadmin/grpc/grpc_tools.protoc-args +++ b/pymapadmin/grpc/grpc_tools.protoc-args @@ -1,5 +1,5 @@ -I. --python_out=. ---python_grpc_out=. +--grpclib_python_out=. --mypy_out=. pymapadmin/grpc/admin.proto diff --git a/pymapadmin/typing.py b/pymapadmin/typing.py index 9078fc6..16b3585 100644 --- a/pymapadmin/typing.py +++ b/pymapadmin/typing.py @@ -11,16 +11,22 @@ from .grpc.admin_pb2 import Result __all__ = ['StubT', 'RequestT', 'ResponseT', 'MethodProtocol', - 'RequestProtocol', 'ResponseProtocol'] + 'AdminRequestProtocol', 'AdminResponseProtocol'] #: A type variable corresponding to an admin stub object. StubT = TypeVar('StubT') +#: A type variable corresponding to an request object. +RequestT = TypeVar('RequestT') + +#: A type variable corresponding to an response object. +ResponseT = TypeVar('ResponseT') + #: A type variable corresponding to an admin request object. -RequestT = TypeVar('RequestT', bound='RequestProtocol') +AdminRequestT = TypeVar('AdminRequestT', bound='AdminRequestProtocol') #: A type variable corresponding to an admin response object. -ResponseT = TypeVar('ResponseT', bound='ResponseProtocol') +AdminResponseT = TypeVar('AdminResponseT', bound='AdminResponseProtocol') class MethodProtocol(Protocol[RequestT, ResponseT]): @@ -32,7 +38,7 @@ def open(self, *, metadata: Mapping[str, str]) \ ... -class RequestProtocol(Protocol): +class AdminRequestProtocol(Protocol): """Protocol defining the fields that all admin request objects are expected to have. @@ -43,7 +49,7 @@ class RequestProtocol(Protocol): pass -class ResponseProtocol(Protocol): +class AdminResponseProtocol(Protocol): """Protocol defining the fields that all admin response objects are expected to have. diff --git a/requirements-dev.txt b/requirements-dev.txt index b931292..4e1c78a 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -6,6 +6,10 @@ pytest-asyncio pytest-cov rope +# unreleased typing changes +grpclib == 0.4.3rc1 + +# stubs types-setuptools -r requirements-all.txt diff --git a/setup.py b/setup.py index 3315f3e..701aed4 100644 --- a/setup.py +++ b/setup.py @@ -29,7 +29,7 @@ setup(name='pymap-admin', - version='0.7.1', + version='0.8.0', author='Ian Good', author_email='ian@icgood.net', description='Admin tool for running pymap instances.', @@ -45,8 +45,8 @@ 'Intended Audience :: Information Technology', 'License :: OSI Approved :: MIT License', 'Programming Language :: Python', - 'Programming Language :: Python :: 3.9'], - python_requires='~=3.9', + 'Programming Language :: Python :: 3.10'], + python_requires='~=3.10', include_package_data=True, packages=find_packages(), install_requires=[ @@ -58,6 +58,7 @@ 'console_scripts': [ 'pymap-admin = pymapadmin.main:main'], 'pymapadmin.commands': [ + 'check = pymapadmin.commands.health:CheckCommand', 'save-args = pymapadmin.commands.system:SaveArgsCommand', 'login = pymapadmin.commands.system:LoginCommand', 'ping = pymapadmin.commands.system:PingCommand', diff --git a/test/test_health.py b/test/test_health.py new file mode 100644 index 0000000..6c7f145 --- /dev/null +++ b/test/test_health.py @@ -0,0 +1,44 @@ + +from io import StringIO +from argparse import Namespace + +import pytest +from grpclib.testing import ChannelFor +from pymapadmin.commands.health import CheckCommand +from grpclib.health.v1.health_grpc import HealthBase +from grpclib.health.v1.health_pb2 import HealthCheckRequest, \ + HealthCheckResponse + +from handler import RequestT, ResponseT, MockHandler + +pytestmark = pytest.mark.asyncio + + +class Handler(HealthBase, MockHandler[RequestT, ResponseT]): + + async def Check(self, stream) -> None: + await self._run(stream) + + async def Watch(self, stream) -> None: + raise NotImplementedError() + + +class TestCheckCommand: + + async def test_check(self) -> None: + handler = Handler(HealthCheckRequest, [HealthCheckResponse( + status=HealthCheckResponse.ServingStatus.SERVING)]) + args = Namespace(token=None, token_file=None) + async with ChannelFor([handler]) as channel: + command = CheckCommand(args, channel) + code = await command(StringIO()) + assert 0 == code + + async def test_check_not_serving(self) -> None: + handler = Handler(HealthCheckRequest, [HealthCheckResponse( + status=HealthCheckResponse.ServingStatus.NOT_SERVING)]) + args = Namespace(token=None, token_file=None) + async with ChannelFor([handler]) as channel: + command = CheckCommand(args, channel) + code = await command(StringIO()) + assert 1 == code