Skip to content

Commit 75a79dd

Browse files
PubNub SDK v4.7.0 release.
1 parent 11a2249 commit 75a79dd

40 files changed

+901
-383
lines changed

.pubnub.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
name: python
2-
version: 4.6.1
2+
version: 4.7.0
33
schema: 1
44
scm: github.com/pubnub/python
55
changelog:
6+
- version: v4
7+
date: Nov 19, 2020
8+
changes:
9+
-
10+
text: "Within this release problems with double PAM calls encoding and Publish oriented bugs were fixed."
11+
type: bug
612
- version: v4.6.1
713
date: Oct 27, 2020
814
changes:

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## [v4](https://github.com/pubnub/python/releases/tag/v4)
2+
3+
[Full Changelog](https://github.com/pubnub/python/compare/v4.6.1...v4)
4+
5+
- 🐛 Within this release problems with double PAM calls encoding and Publish oriented bugs were fixed.
6+
17
## [v4.6.1](https://github.com/pubnub/python/releases/tag/v4.6.1)
28

39
[Full Changelog](https://github.com/pubnub/python/compare/v4.6.0...v4.6.1)

README.md

Lines changed: 80 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,92 @@
11
# PubNub Python SDK (V4)
2+
23
[![Build Status](https://travis-ci.org/pubnub/python.svg?branch=master)](https://travis-ci.org/pubnub/python)
34
[![codecov](https://codecov.io/gh/pubnub/python/branch/master/graph/badge.svg)](https://codecov.io/gh/pubnub/python)
45
[![PyPI](https://img.shields.io/pypi/v/pubnub.svg)](https://pypi.python.org/pypi/pubnub/)
56
[![PyPI](https://img.shields.io/pypi/pyversions/pubnub.svg)](https://pypi.python.org/pypi/pubnub/)
67
[![Docs](https://img.shields.io/badge/docs-online-blue.svg)](https://www.pubnub.com/docs/python/pubnub-python-sdk-v4)
78

8-
The SDK supports Python 2.7, 3.4, 3.5, 3.6, 3.7 and pypy.
9+
This is the official PubNub Python SDK repository.
10+
11+
PubNub takes care of the infrastructure and APIs needed for the realtime communication layer of your application. Work on your app's logic and let PubNub handle sending and receiving data across the world in less than 100ms.
12+
13+
## Get keys
14+
15+
You will need the publish and subscribe keys to authenticate your app. Get your keys from the [Admin Portal](https://dashboard.pubnub.com/login).
16+
17+
## Configure PubNub
18+
19+
1. Integrate the Python SDK into your project using `pip`:
20+
21+
```bash
22+
pip install pubnub
23+
```
24+
25+
2. Configure your keys:
26+
27+
```python
28+
pnconfig = PNConfiguration()
29+
30+
pnconfig.subscribe_key = 'mySubscribeKey'
31+
pnconfig.publish_key = 'myPublishKey'
32+
pnconfig.uuid = 'myUniqueUUID'
33+
pubnub = PubNub(pnconfig)
34+
```
35+
36+
## Add event listeners
37+
38+
```python
39+
class SubscribeHandler(SubscribeCallback):
40+
def status(self, pubnub, event):
41+
print("Is there an error? ", event.is_error())
42+
print("Status value for category: %s" % event.category)
43+
print("Status value for error_data: %s" % event.error_data)
44+
print("Status value for error: %s" % event.error)
45+
print("Status value for status_code: %s" % event.status_code)
46+
print("Status value for operation: %s" % event.operation)
47+
print("Status value for tls_enabled: %s" % event.tls_enabled)
48+
print("Status value for uuid: %s" % event.uuid)
49+
print("Status value for auth_key: %s" % event.auth_key)
50+
print("Status value for origin: %s" % event.origin)
51+
print("Status value for client_request: %s" % event.client_request)
52+
print("Status value for client_response: %s" % event.client_response)
53+
print("Status value for original_response: %s" % event.original_response)
54+
print("Status value for affected_channels: %s" % event.affected_channels)
55+
print("Status value for affected_groups: %s" % event.affected_groups)
56+
57+
def presence(self, pubnub, presence):
58+
pass # Handle incoming presence data
59+
60+
def message(self, pubnub, message):
61+
pass # Handle incoming messages
62+
63+
def signal(self, pubnub, signal):
64+
pass # Handle incoming signals
65+
66+
pubnub.add_listener(SubscribeHandler())
67+
```
68+
69+
## Publish/subscribe
70+
71+
```python
72+
def my_publish_callback(envelope, status):
73+
if status.is_error():
74+
... #handle error here
75+
else:
76+
... #handle result here
77+
78+
pubnub.publish().channel('my_channel').message('Hello world!').pn_async(my_publish_callback)
79+
80+
pubnub.subscribe().channels('my_channel').execute()
81+
```
982
1083
## Documentation
1184
12-
Please review our documentation and examples on the [PubNub Website](https://www.pubnub.com/docs/python/pubnub-python-sdk-v4)
85+
* [Build your first realtime Python app with PubNub](https://www.pubnub.com/docs/platform/quickstarts/python)
86+
* [API reference for Python](https://www.pubnub.com/docs/python/pubnub-python-sdk)
87+
* [API reference for Python (Tornado)](https://www.pubnub.com/docs/python-tornado/pubnub-python-sdk)
88+
* [API reference for Python (asyncio)](https://www.pubnub.com/docs/python-aiohttp/pubnub-python-sdk)
1389
14-
## Communication
90+
## Support
1591
16-
- If you **need help** or have a **general question**, contact <[email protected]>
92+
If you **need help** or have a **general question**, contact [email protected].

pubnub/endpoints/access/grant.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,20 @@ def ttl(self, ttl):
5454
self._ttl = ttl
5555
return self
5656

57+
def encoded_params(self):
58+
params = {}
59+
60+
if self._auth_keys:
61+
params['auth'] = utils.join_items_and_encode(self._auth_keys)
62+
63+
if self._channels:
64+
params['channel'] = utils.join_channels(self._channels)
65+
66+
if self._groups:
67+
params['channel-group'] = utils.join_items_and_encode(self._groups)
68+
69+
return params
70+
5771
def custom_params(self):
5872
params = {}
5973

@@ -66,13 +80,13 @@ def custom_params(self):
6680
if self._delete is not None:
6781
params['d'] = '1' if self._delete is True else '0'
6882

69-
if len(self._auth_keys) > 0:
70-
params['auth'] = utils.join_items_and_encode(self._auth_keys)
83+
if self._auth_keys:
84+
params['auth'] = utils.join_items(self._auth_keys)
7185

72-
if len(self._channels) > 0:
86+
if self._channels:
7387
params['channel'] = utils.join_items(self._channels)
7488

75-
if len(self._groups) > 0:
89+
if self._groups:
7690
params['channel-group'] = utils.join_items(self._groups)
7791

7892
if self._ttl is not None:

pubnub/endpoints/endpoint.py

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import logging
44

55
from pubnub import utils
6-
from pubnub.enums import PNStatusCategory, PNOperationType
6+
from pubnub.enums import PNStatusCategory
77
from pubnub.errors import (
88
PNERR_SUBSCRIBE_KEY_MISSING, PNERR_PUBLISH_KEY_MISSING, PNERR_CHANNEL_OR_GROUP_MISSING,
99
PNERR_SECRET_KEY_MISSING, PNERR_CHANNEL_MISSING, PNERR_FILE_OBJECT_MISSING,
@@ -99,6 +99,9 @@ def build_file_upload_request(self):
9999
def non_json_response(self):
100100
return False
101101

102+
def encoded_params(self):
103+
return {}
104+
102105
def options(self):
103106
return RequestOptions(
104107
path=self.build_path(),
@@ -171,7 +174,6 @@ def handler():
171174

172175
def build_params_callback(self):
173176
def callback(params_to_merge):
174-
operation_type = self.operation_type()
175177
custom_params = self.custom_params()
176178
custom_params.update(params_to_merge)
177179

@@ -196,11 +198,7 @@ def callback(params_to_merge):
196198
if self.pubnub.config.secret_key is not None:
197199
utils.sign_request(self, self.pubnub, custom_params, self.http_method(), self.build_data())
198200

199-
# REVIEW: add encoder map to not hardcode encoding here
200-
if operation_type == PNOperationType.PNPublishOperation and 'meta' in custom_params:
201-
custom_params['meta'] = utils.url_encode(custom_params['meta'])
202-
if operation_type == PNOperationType.PNSetStateOperation and 'state' in custom_params:
203-
custom_params['state'] = utils.url_encode(custom_params['state'])
201+
custom_params.update(self.encoded_params())
204202

205203
# reassign since pnsdk should be signed unencoded
206204
custom_params['pnsdk'] = utils.url_encode(self.pubnub.sdk_name)
@@ -268,7 +266,7 @@ def create_status(self, category, response, response_info, exception):
268266
pn_status.operation = self.operation_type()
269267
pn_status.category = category
270268
pn_status.affected_channels = self.affected_channels()
271-
pn_status.affected_channels_groups = self.affected_channels_groups()
269+
pn_status.affected_groups = self.affected_channels_groups()
272270

273271
return pn_status
274272

pubnub/endpoints/file_operations/publish_file_message.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
from pubnub.enums import HttpMethod, PNOperationType
33
from pubnub import utils
44
from pubnub.models.consumer.file import PNPublishFileMessageResult
5+
from pubnub.endpoints.mixins import TimeTokenOverrideMixin
56

67

7-
class PublishFileMessage(FileOperationEndpoint):
8+
class PublishFileMessage(FileOperationEndpoint, TimeTokenOverrideMixin):
89
PUBLISH_FILE_MESSAGE = "/v1/files/publish-file/%s/%s/0/%s/0/%s"
910

1011
def __init__(self, pubnub):
11-
FileOperationEndpoint.__init__(self, pubnub)
12+
super(PublishFileMessage, self).__init__(pubnub)
1213
self._file_id = None
1314
self._file_name = None
1415
self._pubnub = pubnub
@@ -17,6 +18,8 @@ def __init__(self, pubnub):
1718
self._ttl = 0
1819
self._meta = None
1920
self._cipher_key = None
21+
self._replicate = None
22+
self._ptto = None
2023

2124
def meta(self, meta):
2225
self._meta = meta
@@ -79,11 +82,13 @@ def http_method(self):
7982
return HttpMethod.GET
8083

8184
def custom_params(self):
82-
return {
85+
params = TimeTokenOverrideMixin.custom_params(self)
86+
params.update({
8387
"meta": utils.url_write(self._meta),
8488
"ttl": self._ttl,
85-
"store": self._should_store
86-
}
89+
"store": 1 if self._should_store else 0
90+
})
91+
return params
8792

8893
def is_auth_required(self):
8994
return True

pubnub/endpoints/file_operations/send_file.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,12 @@
77
from pubnub.endpoints.file_operations.publish_file_message import PublishFileMessage
88
from pubnub.endpoints.file_operations.fetch_upload_details import FetchFileUploadS3Data
99
from pubnub.request_handlers.requests_handler import RequestsRequestHandler
10+
from pubnub.endpoints.mixins import TimeTokenOverrideMixin
1011

1112

12-
class SendFileNative(FileOperationEndpoint):
13+
class SendFileNative(FileOperationEndpoint, TimeTokenOverrideMixin):
1314
def __init__(self, pubnub):
14-
FileOperationEndpoint.__init__(self, pubnub)
15+
super(SendFileNative, self).__init__(pubnub)
1516
self._file_name = None
1617
self._pubnub = pubnub
1718
self._file_upload_envelope = None
@@ -21,6 +22,8 @@ def __init__(self, pubnub):
2122
self._meta = None
2223
self._cipher_key = None
2324
self._file_object = None
25+
self._replicate = None
26+
self._ptto = None
2427

2528
def file_object(self, fd):
2629
self._file_object = fd
@@ -128,6 +131,8 @@ def sync(self):
128131
file_name(response_envelope.result.name).\
129132
should_store(self._should_store).\
130133
ttl(self._ttl).\
134+
replicate(self._replicate).\
135+
ptto(self._ptto).\
131136
cipher_key(self._cipher_key).sync()
132137

133138
response_envelope.result.timestamp = publish_file_response.result.timestamp

pubnub/endpoints/mixins.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import six
2+
3+
from pubnub.errors import PNERR_UUID_MISSING
4+
from pubnub.exceptions import PubNubException
5+
6+
7+
class UUIDValidatorMixin:
8+
def validate_uuid(self):
9+
if self._uuid is None or not isinstance(self._uuid, six.string_types):
10+
raise PubNubException(pn_error=PNERR_UUID_MISSING)
11+
12+
13+
class TimeTokenOverrideMixin:
14+
def replicate(self, replicate):
15+
self._replicate = replicate
16+
return self
17+
18+
def ptto(self, timetoken):
19+
if timetoken:
20+
assert isinstance(timetoken, six.integer_types)
21+
self._ptto = timetoken
22+
return self
23+
24+
def custom_params(self):
25+
params = {}
26+
if self._replicate is not None:
27+
if self._replicate:
28+
params["norep"] = "false"
29+
else:
30+
params["norep"] = "true"
31+
32+
if self._ptto:
33+
params["ptto"] = self._ptto
34+
35+
return params

pubnub/endpoints/presence/get_state.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from pubnub.endpoints.endpoint import Endpoint
33
from pubnub.enums import HttpMethod, PNOperationType
44
from pubnub.models.consumer.presence import PNGetStateResult
5-
from pubnub.endpoints.validators import UUIDValidatorMixin
5+
from pubnub.endpoints.mixins import UUIDValidatorMixin
66

77

88
class GetState(Endpoint, UUIDValidatorMixin):

pubnub/endpoints/presence/set_state.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ def state(self, state):
3030
self._state = state
3131
return self
3232

33+
def encoded_params(self):
34+
return {
35+
"state": utils.url_write(self._state)
36+
}
37+
3338
def custom_params(self):
3439
if self._subscription_manager is not None:
3540
self._subscription_manager.adapt_state_builder(StateOperation(

0 commit comments

Comments
 (0)