Skip to content

Releases: frequenz-floss/frequenz-client-base-python

v0.11.1

02 Sep 09:31
Immutable release. Only release title and notes can be modified.
v0.11.1
4afe440

Choose a tag to compare

Frequenz Client Base Library Release Notes

Warning

This version has a bug in the streaming module that makes any stream using GrpcStreamBroadcaster not receive any data. The version was yanked from PyPI and should not be used.

Upgrading

  • There is very minor breaking change in this release, GrpcStreamBroadcaster now requires a grpc.aio.UnaryStreamCall instead of a AsyncIterable for the stream_method argument. In practice all users should be passing a grpc.aio.UnaryStreamCall already, so this should not affect anyone unless they are doing something very strange.

Bug Fixes

  • GrpcStreamBroadcaster: Fix potential long delays on retries, and giving up early if the number of retries is limited.

    The retry strategy was not reset after a successful start of the stream, so the back-off delays would accumulate over multiple retries and eventually give up if the number of retries were limited, even if there was a successful start of the stream in between. Now we properly reset the retry strategy after a successful start of the stream (successfully receiving the first item from the stream).

  • GrpcStreamBroadcaster: Fix StreamStarted event firing too soon.

    The StreamStarted event was being fired as soon as the streamming method was called, but that doesn't mean that a streamming connection was established with the server at all, which can give a false impression that the stream is active and working. Now we wait until we receive the initial metadata from the server before firing the StreamStarted event. That should give users a better indication that the stream is actually active and working without having to wait for the first item to be received, which can take a long time for some low-frequency streams.

What's Changed

  • Improve the README by @llucax in #157
  • Bump pytest-asyncio from 0.26.0 to 1.0.0 by @dependabot[bot] in #159
  • Bump the patch group with 6 updates by @dependabot[bot] in #160
  • Bump pytest-asyncio from 1.0.0 to 1.1.0 by @dependabot[bot] in #166
  • Bump the compatible group with 2 updates by @dependabot[bot] in #163
  • Bump async-solipsism from 0.7 to 0.8 by @dependabot[bot] in #165
  • Bump mkdocstrings[python] from 0.29.1 to 0.30.0 in the mkdocstrings group by @dependabot[bot] in #164
  • Bump pydoclint from 0.6.6 to 0.6.11 by @dependabot[bot] in #170
  • Bump actions/checkout from 4 to 5 by @dependabot[bot] in #171
  • Bump actions/download-artifact from 4 to 5 in the artifacts group by @dependabot[bot] in #168
  • Bump mkdocstrings-python from 1.16.12 to 1.18.2 in the mkdocstrings group by @dependabot[bot] in #169
  • Add missing retry strategy reset in streaming by @llucax in #148

Full Changelog: v0.11.0...v0.11.1

v0.11.0

10 Jun 12:31
Immutable release. Only release title and notes can be modified.
v0.11.0
b3a0d31

Choose a tag to compare

Frequenz Client Base Library Release Notes

Summary

Upgrading

  • Updated interface and behavior for HMAC

    This introduces a new positional argument to parse_grpc_uri.
    If calling this function manually and passing ChannelOptions, it is recommended
    to switch to passing ChannelOptions via keyword argument.

  • All parameters of the Streamers new_receiver method are now keyword-only arguments. This means that you must specify them by name when calling the method, e.g.:

    recv = streamer.new_receiver(max_size=50, warn_on_overflow=True)

New Features

  • The streaming client, when using new_receiver(include_events=True), will now return a receiver that yields stream notification events, such as StreamStarted, StreamRetrying, and StreamFatalError. This allows you to monitor the state of the stream:

    recv = streamer.new_receiver(include_events=True)
    
    for msg in recv:
        match msg:
            case StreamStarted():
                print("Stream started")
            case StreamRetrying(delay, error):
                print(f"Stream stopped and will retry in {delay}: {error or 'closed'}")
            case StreamFatalError(error):
                print(f"Stream will stop because of a fatal error: {error}")
            case int() as output:
                print(f"Received message: {output}")

Bug Fixes

What's Changed

Full Changelog: v0.10.0...v0.11.0

v0.10.0

23 May 09:59
v0.10.0
3985408

Choose a tag to compare

Frequenz Client Base Library Release Notes

Features

  • Added support for HMAC signing of UnaryUnary client messages
  • Added support for HMAC signing of UnaryStream client messages

Upgrading

  • Updated protobuf dependency range: changed from >=4.21.6, <6 to >=5.29.2, <7
  • The minimum dependency for typing-extensions is now 4.6.0 to be compatible with Python 3.12
  • The minimum dependency for grpcio is now 1.59 to be compatible with Python 3.12

Bug Fixes

  • Fixed keys of signature to match what fuse-rs expects

  • GrpcStreamBroadcaster will now correctly try to restart on unexpected errors.

    Before if an unexpected exception was raised by the stream method, the
    internal task would silently finish and never start again.

What's Changed

New Contributors

Full Changelog: v0.9.0...v0.10.0

v0.9.0

19 Feb 13:07
v0.9.0
f0d7f07

Choose a tag to compare

Frequenz Client Base Library Release Notes

Upgrading

  • The minimum required version of frequenz-channels is now v1.6.1.

New Features

  • Add the warn_on_overflow option to the streaming receivers to allow ignoring overflow warnings

What's Changed

New Contributors

Full Changelog: v0.8.1...v0.9.0

v0.8.1

19 Nov 13:38
v0.8.1
b9cb307

Choose a tag to compare

Frequenz Client Base Library Release Notes

Summary

This release adds some arguments that were missing in the parse_grpc_uri() function's documentation.

What's Changed

  • Clear release notes by @llucax in #97
  • Remove unnecessary --platform flag in Dockerfile by @llucax in #98
  • Update parse_grpc_uri docs with keep-alive params by @shsms in #99

Full Changelog: v0.8.0...v0.8.1

v0.8.0

19 Nov 08:49
v0.8.0
f03d3e5

Choose a tag to compare

Frequenz Client Base Library Release Notes

Upgrading

The BaseApiClient class is generic again. There was too many issues with the new approach, so it was rolled back.

  • If you are upgrading from v0.7.x, you should be able to roll back your changes with the upgrade and just keep the new stub property.

    # Old
    from __future__ import annotations
    import my_service_pb2_grpc
    class MyApiClient(BaseApiClient):
       def __init__(self, server_url: str, *, ...) -> None:
           super().__init__(server_url, ...)
           stub = my_service_pb2_grpc.MyServiceStub(self.channel)
           self._stub: my_service_pb2_grpc.MyServiceAsyncStub = stub  # type: ignore
           ...
    
       @property
       def stub(self) -> my_service_pb2_grpc.MyServiceAsyncStub:
           if self.channel is None:
               raise ClientNotConnected(server_url=self.server_url, operation="stub")
           return self._stub
    
    # New
    from __future__ import annotations
    import my_service_pb2_grpc
    from my_service_pb2_grpc import MyServiceStub
    class MyApiClient(BaseApiClient[MyServiceStub]):
       def __init__(self, server_url: str, *, ...) -> None:
           super().__init__(server_url, MyServiceStub, ...)
           ...
    
       @property
       def stub(self) -> my_service_pb2_grpc.MyServiceAsyncStub:
           """The gRPC stub for the API."""
           if self.channel is None or self._stub is None:
               raise ClientNotConnected(server_url=self.server_url, operation="stub")
           # This type: ignore is needed because we need to cast the sync stub to
           # the async stub, but we can't use cast because the async stub doesn't
           # actually exists to the eyes of the interpreter, it only exists for the
           # type-checker, so it can only be used for type hints.
           return self._stub  # type: ignore
  • If you are upgrading from v0.6.x, you should only need to add the stub property to your client class and then use that property instead of _stub in your code.

       @property
       def stub(self) -> my_service_pb2_grpc.MyServiceAsyncStub:
           """The gRPC stub for the API."""
           if self.channel is None or self._stub is None:
               raise ClientNotConnected(server_url=self.server_url, operation="stub")
           # This type: ignore is needed because we need to cast the sync stub to
           # the async stub, but we can't use cast because the async stub doesn't
           # actually exists to the eyes of the interpreter, it only exists for the
           # type-checker, so it can only be used for type hints.
           return self._stub  # type: ignore

What's Changed

  • Clear release notes by @shsms in #94
  • Bump the required group with 9 updates by @dependabot in #95
  • Revert "Remove generic type from BaseApiClient" by @llucax in #96

Full Changelog: v0.7.0...v0.8.0

v0.7.0

29 Oct 13:30
v0.7.0
3d35fe7

Choose a tag to compare

Frequenz Client Base Library Release Notes

Summary

This release improves the BaseApiClient interface and introduces HTTP2 keep-alive, among other changes.

Upgrading

  • GrpcStreamBroadcaster now takes a AsyncIterable instead of a AsyncIterator as the stream_method. This is to match the type of streaming methods generated by grpc, so no conversion to an AsyncIterator is needed.

  • GrpcStreamBroadcaster no longer tries to reconnect when a server closes a connection. This behaviour can be overridden by passing retry_on_exhausted_stream=True when constructing GrpcStreamBroadcaster instances.

  • gRPC URLs don't have a default port anymore, unless a default is set via ChannelOptions. If you want to set a default port for URLs, please pass custom ChannelOptions as defaults to parse_grpc_uri or as channel_defaults to BaseApiClient.

  • The ExponentialBackoff and LinearBackoff classes now require keyword arguments for their constructor. This change was made to make the classes easier to use and to avoid confusion with the order of the arguments.
  • HTTP2 keep-alive is now enabled by default, with an interval of 60 seconds between pings, and a 20 second timeout for responses from the service. These values are configurable and may be updated based on specific requirements.
  • The BaseApiClient class is not generic anymore, and doesn't take a function to create the stub. Instead, subclasses should create their own stub right after calling the parent constructor. This enables subclasses to cast the stub to the generated XxxAsyncStub class, which have proper async type hints. To convert you client:

    # Old
    from my_service_pb2_grpc import MyServiceStub
    class MyApiClient(BaseApiClient[MyServiceStub]):
        def __init__(self, server_url: str, *, ...) -> None:
            super().__init__(server_url, MyServiceStub, ...)
            ...
    
    # New
    from __future__ import annotations
    import my_service_pb2_grpc
    class MyApiClient(BaseApiClient):
        def __init__(self, server_url: str, *, ...) -> None:
            super().__init__(server_url, connect=connect)
            stub = my_service_pb2_grpc.MyServiceStub(self.channel)
            # We need the type: ignore here because the generated async stub only lives in
            # the .pyi file (the interpreter doesn't know anything about it) so we can't use
            # a proper `cast()`, we can only use the async stub as a type hint.
            self._stub: my_service_pb2_grpc.MyServiceAsyncStub = stub  # type: ignore
            ...
    
        @property
        def stub(self) -> my_service_pb2_grpc.MyServiceAsyncStub:
            if self.channel is None:
                raise ClientNotConnected(server_url=self.server_url, operation="stub")
            return self._stub

    You probably also need to ignore the no-member check from pylint, as pylint doesn't read *.pyi files, so it won't find the async stub and complain.

    [tool.pylint.messages_control]
    disable = [
      # [..]
      # Checked by mypy
      "no-member",
      # [..]
    ]

    After this, you should be able to remove a lot of casts or type: ignore from the code when calling the stub async methods.

New Features

  • Added support for HTTP2 keep-alive.

What's Changed

  • Clear release notes by @shsms in #83
  • Replace the stream_method return to AsyncIterable by @llucax in #87
  • Don't allow a default port in URLs by default by @llucax in #85
  • Bump the required group with 9 updates by @dependabot in #89
  • Don't retry by default when the stream is exhausted by @shsms in #91
  • Support http2 keep-alive by @shsms in #90
  • Remove generic type from BaseApiClient by @llucax in #92
  • Prepare for v0.7.0 by @shsms in #93

Full Changelog: v0.6.1...v0.7.0

v0.6.1

03 Sep 09:47
v0.6.1
1eec18a

Choose a tag to compare

Frequenz Client Base Library Release Notes

Bug Fixes

  • Fixes a bug in creating grpc channels from ipv6 URIs.

What's Changed

  • Clear release notes by @llucax in #76
  • Bump the required group with 9 updates by @dependabot in #78
  • Use netloc from urlparse to specify the host by @shsms in #79
  • Prepare release notes for v0.6.1 by @shsms in #82

Full Changelog: v0.6.0...v0.6.1

v0.6.0

26 Aug 10:41
v0.6.0
e1c02e5

Choose a tag to compare

Frequenz Client Base Library Release Notes

Summary

This version removes grpclib support and adds new SSL options to the connection URI.

Upgrading

  • grpclib was removed, if you used grpclib you should switch to grpcio instead.

    You should also update your dependency to frequenz-client-base (without any [grpclib] or [grpcio] suffix). Also, now there is no need to pass around the channel type to the BaseApiClient or the parse_grpc_uri function.

  • The parse_grpc_uri function (and BaseApiClient constructor) now enables SSL by default (ssl=false should be passed to disable it).

  • The parse_grpc_uri and BaseApiClient function now accepts a set of defaults to use when the URI does not specify a value for a given option.

New Features

  • The connection URI can now have a few new SSL options:

    • ssl_root_certificates_path to specify the path to the root certificates file.
    • ssl_private_key_path to specify the path to the private key file.
    • ssl_certificate_chain_path to specify the path to the certificate chain file.

What's Changed

Full Changelog: v0.5.0...v0.6.0

v0.5.0

26 Jul 08:29
v0.5.0
0553ddc

Choose a tag to compare

Frequenz Client Base Library Release Notes

Summary

The main features of this release is the new base class for API clients, gRPC exception wrappers and a new utility function to call stub methods.

Upgrading

  • channel.parse_grpc_uri() takes an extra argument, the channel type (which can be either grpclib.client.Channel or grpcio.aio.Channel).

New Features

  • Add a exception module to provide client exceptions, including gRPC errors with one subclass per gRPC error status code.
  • channel.parse_grpc_uri() can now be used with grpcio too.
  • A new BaseApiClient class is introduced to provide a base class for API clients. It is strongly recommended to use this class as a base class for all API clients.
  • A new call_stub_method() function to simplify calling stub methods, converting gRPC errors to ApiClientErrors, checking if the client is connected and optionally wrapping the response.

What's Changed

  • Clear the release notes by @llucax in #53
  • Add client exceptions by @llucax in #55
  • Bump the required group with 7 updates by @dependabot in #57
  • Add grpcio support to parse_grpc_uri() by @llucax in #54
  • Add a BaseApiClient class by @llucax in #56
  • Improve type-checking for _grpchacks by @llucax in #59
  • Add a function to call gRPC stubs and wrap errors by @llucax in #58
  • Bump docker/build-push-action from 5 to 6 by @dependabot in #61
  • Bump the required group with 9 updates by @dependabot in #60
  • Bump brettcannon/check-for-changed-files from 1.2.0 to 1.2.1 by @dependabot in #62
  • Prepare release notes for the 0.5 release by @llucax in #63

Full Changelog: v0.4.0...v0.5.0