Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add type hints to customer facing interfaces #195

Merged
merged 4 commits into from
Oct 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions .pubnub.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: python
version: 8.1.0
version: 9.0.0
schema: 1
scm: github.com/pubnub/python
sdks:
Expand All @@ -18,7 +18,7 @@ sdks:
distributions:
- distribution-type: library
distribution-repository: package
package-name: pubnub-8.1.0
package-name: pubnub-9.0.0
location: https://pypi.org/project/pubnub/
supported-platforms:
supported-operating-systems:
Expand Down Expand Up @@ -97,8 +97,8 @@ sdks:
-
distribution-type: library
distribution-repository: git release
package-name: pubnub-8.1.0
location: https://github.com/pubnub/python/releases/download/v8.1.0/pubnub-8.1.0.tar.gz
package-name: pubnub-9.0.0
location: https://github.com/pubnub/python/releases/download/v9.0.0/pubnub-9.0.0.tar.gz
supported-platforms:
supported-operating-systems:
Linux:
Expand Down Expand Up @@ -169,6 +169,19 @@ sdks:
license-url: https://github.com/aio-libs/aiohttp/blob/master/LICENSE.txt
is-required: Required
changelog:
- date: 2024-10-02
version: v9.0.0
changes:
- type: feature
text: "BREAKING CHANGES: Automatic reconnecting for subscribe with exponential backoff is now enabled by default."
- type: feature
text: "Access manager v2 endpoints (grant and audit) will no longer be supported after December 31, 2024, and will be removed without further notice. Refer to the documentation to learn more."
- type: feature
text: "BREAKING CHANGES: Once used to instantiate PubNub, the configuration object (PNConfiguration instance) becomes immutable. You will receive exceptions if you rely on modifying the configuration after the PubNub instance is created. Refer to the documentation to learn more."
- type: improvement
text: "Type hints for parameters and return values are now added to provide a better developer experience."
- type: improvement
text: "All endpoints are now accessible through the builder pattern and named parameters, providing a more flexible experience suitable for custom solutions."
- date: 2024-08-13
version: v8.1.0
changes:
Expand Down
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
## v9.0.0
October 02 2024

#### Added
- BREAKING CHANGES: Automatic reconnecting for subscribe with exponential backoff is now enabled by default.
- Access manager v2 endpoints (grant and audit) will no longer be supported after December 31, 2024, and will be removed without further notice. Refer to the documentation to learn more.
- BREAKING CHANGES: Once used to instantiate PubNub, the configuration object (PNConfiguration instance) becomes immutable. You will receive exceptions if you rely on modifying the configuration after the PubNub instance is created. Refer to the documentation to learn more.

#### Modified
- Type hints for parameters and return values are now added to provide a better developer experience.
- All endpoints are now accessible through the builder pattern and named parameters, providing a more flexible experience suitable for custom solutions.

## v8.1.0
August 13 2024

Expand Down
50 changes: 36 additions & 14 deletions pubnub/endpoints/access/grant_token.py
Original file line number Diff line number Diff line change
@@ -1,58 +1,77 @@
from typing import Union, List, Optional
from pubnub import utils
from pubnub.endpoints.endpoint import Endpoint
from pubnub.errors import PNERR_TTL_MISSING, PNERR_INVALID_META, PNERR_RESOURCES_MISSING
from pubnub.exceptions import PubNubException
from pubnub.enums import HttpMethod, PNOperationType
from pubnub.models.consumer.common import PNStatus
from pubnub.models.consumer.v3.access_manager import PNGrantTokenResult
from pubnub.structures import Envelope


class PNGrantTokenResultEnvelope(Envelope):
result: PNGrantTokenResult
status: PNStatus


class GrantToken(Endpoint):
GRANT_TOKEN_PATH = "/v3/pam/%s/grant"

def __init__(self, pubnub):
def __init__(self, pubnub, channels: Union[str, List[str]] = None, channel_groups: Union[str, List[str]] = None,
users: Union[str, List[str]] = None, spaces: Union[str, List[str]] = None,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you need users and spaces parameters?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the users and spaces were already in there so I just bubbled them up to the constructor

authorized_user_id: str = None, ttl: Optional[int] = None, meta: Optional[any] = None):
Endpoint.__init__(self, pubnub)
self._ttl = None
self._meta = None
self._authorized_uuid = None
self._ttl = ttl
self._meta = meta
self._authorized_uuid = authorized_user_id
self._channels = []
if channels:
utils.extend_list(self._channels, channels)
if spaces:
utils.extend_list(self._channels, spaces)

self._groups = []
if channel_groups:
utils.extend_list(self._groups, channel_groups)
self._uuids = []
if users:
utils.extend_list(self._uuids, users)

self._sort_params = True

def ttl(self, ttl):
def ttl(self, ttl: int) -> 'GrantToken':

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it a common pattern to extract a variable that repeats into constants?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah. this is python's way of saying :

def ttl(self, ttl): # <-this is a setter
    self._ttl # <- this is a "protected" property

self._ttl = ttl
return self

def meta(self, meta):
def meta(self, meta: any) -> 'GrantToken':
self._meta = meta
return self

def authorized_uuid(self, uuid):
def authorized_uuid(self, uuid: str) -> 'GrantToken':
self._authorized_uuid = uuid
return self

def authorized_user(self, user):
def authorized_user(self, user) -> 'GrantToken':
self._authorized_uuid = user
return self

def spaces(self, spaces):
def spaces(self, spaces: Union[str, List[str]]) -> 'GrantToken':
self._channels = spaces
return self

def users(self, users):
def users(self, users: Union[str, List[str]]) -> 'GrantToken':
self._uuids = users
return self

def channels(self, channels):
def channels(self, channels: Union[str, List[str]]) -> 'GrantToken':
self._channels = channels
return self

def groups(self, groups):
def groups(self, groups: Union[str, List[str]]) -> 'GrantToken':
self._groups = groups
return self

def uuids(self, uuids):
def uuids(self, uuids: Union[str, List[str]]) -> 'GrantToken':
self._uuids = uuids
return self

Expand Down Expand Up @@ -102,9 +121,12 @@ def validate_params(self):
self.validate_ttl()
self.validate_resources()

def create_response(self, envelope):
def create_response(self, envelope) -> PNGrantTokenResult:
return PNGrantTokenResult.from_json(envelope['data'])

def sync(self) -> PNGrantTokenResultEnvelope:
return PNGrantTokenResultEnvelope(super().sync())

def is_auth_required(self):
return False

Expand Down
12 changes: 11 additions & 1 deletion pubnub/endpoints/access/revoke_token.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
from pubnub.enums import PNOperationType, HttpMethod
from pubnub.endpoints.endpoint import Endpoint
from pubnub.models.consumer.common import PNStatus
from pubnub.models.consumer.v3.access_manager import PNRevokeTokenResult
from pubnub import utils
from pubnub.structures import Envelope


class PNRevokeTokenResultEnvelope(Envelope):
result: PNRevokeTokenResult
status: PNStatus


class RevokeToken(Endpoint):
REVOKE_TOKEN_PATH = "/v3/pam/%s/grant/%s"

def __init__(self, pubnub, token):
def __init__(self, pubnub, token: str):
Endpoint.__init__(self, pubnub)
self.token = token

Expand All @@ -18,6 +25,9 @@ def validate_params(self):
def create_response(self, envelope):
return PNRevokeTokenResult(envelope)

def sync(self) -> PNRevokeTokenResultEnvelope:
return PNRevokeTokenResultEnvelope(super().sync())

def is_auth_required(self):
return False

Expand Down
30 changes: 19 additions & 11 deletions pubnub/endpoints/channel_groups/add_channel_to_channel_group.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,36 @@
from typing import List, Union
from pubnub import utils
from pubnub.endpoints.endpoint import Endpoint
from pubnub.errors import PNERR_CHANNELS_MISSING, PNERR_GROUP_MISSING
from pubnub.exceptions import PubNubException
from pubnub.enums import HttpMethod, PNOperationType
from pubnub.models.consumer.channel_group import PNChannelGroupsAddChannelResult
from pubnub.models.consumer.common import PNStatus
from pubnub.structures import Envelope


class PNChannelGroupsAddChannelResultEnvelope(Envelope):
result: PNChannelGroupsAddChannelResult
status: PNStatus


class AddChannelToChannelGroup(Endpoint):
# /v1/channel-registration/sub-key/<sub_key>/channel-group/<group_name>?add=ch1,ch2
ADD_PATH = "/v1/channel-registration/sub-key/%s/channel-group/%s"

def __init__(self, pubnub):
def __init__(self, pubnub, channels: Union[str, List[str]] = None, channel_group: str = None):
Endpoint.__init__(self, pubnub)
self._channels = []
self._channel_group = None

def channels(self, channels):
if isinstance(channels, (list, tuple)):
self._channels.extend(channels)
else:
self._channels.extend(utils.split_items(channels))
if channels:
utils.extend_list(self._channels, channels)
self._channel_group = channel_group

def channels(self, channels) -> 'AddChannelToChannelGroup':
utils.extend_list(self._channels, channels)
return self

def channel_group(self, channel_group):
def channel_group(self, channel_group: str) -> 'AddChannelToChannelGroup':
self._channel_group = channel_group

return self

def custom_params(self):
Expand All @@ -50,9 +55,12 @@ def validate_params(self):
def is_auth_required(self):
return True

def create_response(self, envelope):
def create_response(self, envelope) -> PNChannelGroupsAddChannelResult:
return PNChannelGroupsAddChannelResult()

def sync(self) -> PNChannelGroupsAddChannelResultEnvelope:
return PNChannelGroupsAddChannelResultEnvelope(super().sync())

def request_timeout(self):
return self.pubnub.config.non_subscribe_request_timeout

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,25 @@
from pubnub.exceptions import PubNubException
from pubnub.enums import HttpMethod, PNOperationType
from pubnub.models.consumer.channel_group import PNChannelGroupsListResult
from pubnub.models.consumer.common import PNStatus
from pubnub.structures import Envelope


class PNChannelGroupsListResultEnvelope(Envelope):
result: PNChannelGroupsListResult
status: PNStatus


class ListChannelsInChannelGroup(Endpoint):
# /v1/channel-registration/sub-key/<sub_key>/channel-group/<group_name>
LIST_PATH = "/v1/channel-registration/sub-key/%s/channel-group/%s"

def __init__(self, pubnub):
def __init__(self, pubnub, channel_group: str = None):
Endpoint.__init__(self, pubnub)
self._channel_group = None

def channel_group(self, channel_group):
self._channel_group = channel_group

def channel_group(self, channel_group: str) -> 'ListChannelsInChannelGroup':
self._channel_group = channel_group
return self

def custom_params(self):
Expand All @@ -35,12 +41,15 @@ def validate_params(self):
if not isinstance(self._channel_group, str) or len(self._channel_group) == 0:
raise PubNubException(pn_error=PNERR_GROUP_MISSING)

def create_response(self, envelope):
def create_response(self, envelope) -> PNChannelGroupsListResult:
if 'payload' in envelope and 'channels' in envelope['payload']:
return PNChannelGroupsListResult(envelope['payload']['channels'])
else:
return PNChannelGroupsListResult([])

def sync(self) -> PNChannelGroupsListResultEnvelope:
return PNChannelGroupsListResultEnvelope(super().sync())

def is_auth_required(self):
return True

Expand Down
Original file line number Diff line number Diff line change
@@ -1,31 +1,38 @@
from typing import List, Union
from pubnub import utils
from pubnub.endpoints.endpoint import Endpoint
from pubnub.errors import PNERR_CHANNELS_MISSING, PNERR_GROUP_MISSING
from pubnub.exceptions import PubNubException
from pubnub.enums import HttpMethod, PNOperationType
from pubnub.models.consumer.channel_group import PNChannelGroupsRemoveChannelResult
from pubnub.models.consumer.common import PNStatus
from pubnub.structures import Envelope


class PNChannelGroupsRemoveChannelResultEnvelope(Envelope):
result: PNChannelGroupsRemoveChannelResult
status: PNStatus


class RemoveChannelFromChannelGroup(Endpoint):
# /v1/channel-registration/sub-key/<sub_key>/channel-group/<group_name>?remove=ch1,ch2
REMOVE_PATH = "/v1/channel-registration/sub-key/%s/channel-group/%s"
_channels: list = []
_channel_group: str = None

def __init__(self, pubnub):
def __init__(self, pubnub, channels: Union[str, List[str]] = None, channel_group: str = None):
Endpoint.__init__(self, pubnub)
self._channels = []
self._channel_group = None

def channels(self, channels):
if isinstance(channels, (list, tuple)):
self._channels.extend(channels)
else:
self._channels.extend(utils.split_items(channels))
if channels:
utils.extend_list(self._channels, channels)
self._channel_group = channel_group

def channels(self, channels) -> 'RemoveChannelFromChannelGroup':
utils.extend_list(self._channels, channels)
return self

def channel_group(self, channel_group):
def channel_group(self, channel_group: str) -> 'RemoveChannelFromChannelGroup':
self._channel_group = channel_group

return self

def custom_params(self):
Expand All @@ -50,9 +57,12 @@ def validate_params(self):
def is_auth_required(self):
return True

def create_response(self, envelope):
def create_response(self, envelope) -> PNChannelGroupsRemoveChannelResult:
return PNChannelGroupsRemoveChannelResult()

def sync(self) -> PNChannelGroupsRemoveChannelResultEnvelope:
return PNChannelGroupsRemoveChannelResultEnvelope(super().sync())

def request_timeout(self):
return self.pubnub.config.non_subscribe_request_timeout

Expand Down
Loading
Loading