Skip to content

Commit 576d2b1

Browse files
Sebastian Molendapubnub-release-bot
andauthored
Introduce limit and next to ListFiles endpoint (#218)
* Introduce limit and next to ListFiles endpoint * Asyncio tests * PubNub SDK 10.4.0 release. --------- Co-authored-by: PubNub Release Bot <[email protected]>
1 parent 0c83b72 commit 576d2b1

20 files changed

+2750
-557
lines changed

.pubnub.yml

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: python
2-
version: 10.3.0
2+
version: 10.4.0
33
schema: 1
44
scm: github.com/pubnub/python
55
sdks:
@@ -18,16 +18,17 @@ sdks:
1818
distributions:
1919
- distribution-type: library
2020
distribution-repository: package
21-
package-name: pubnub-10.3.0
21+
package-name: pubnub-10.4.0
2222
location: https://pypi.org/project/pubnub/
2323
supported-platforms:
2424
supported-operating-systems:
2525
Linux:
2626
runtime-version:
27-
- Python 3.7
28-
- Python 3.8
2927
- Python 3.9
3028
- Python 3.10
29+
- Python 3.11
30+
- Python 3.12
31+
- Python 3.13
3132
minimum-os-version:
3233
- Ubuntu 12.04
3334
maximum-os-version:
@@ -37,10 +38,11 @@ sdks:
3738
- x86-64
3839
macOS:
3940
runtime-version:
40-
- Python 3.7
41-
- Python 3.8
4241
- Python 3.9
4342
- Python 3.10
43+
- Python 3.11
44+
- Python 3.12
45+
- Python 3.13
4446
minimum-os-version:
4547
- macOS 10.12
4648
maximum-os-version:
@@ -49,10 +51,11 @@ sdks:
4951
- x86-64
5052
Windows:
5153
runtime-version:
52-
- Python 3.7
53-
- Python 3.8
5454
- Python 3.9
5555
- Python 3.10
56+
- Python 3.11
57+
- Python 3.12
58+
- Python 3.13
5659
minimum-os-version:
5760
- Windows Vista Ultimate
5861
maximum-os-version:
@@ -91,16 +94,17 @@ sdks:
9194
-
9295
distribution-type: library
9396
distribution-repository: git release
94-
package-name: pubnub-10.3.0
95-
location: https://github.com/pubnub/python/releases/download/10.3.0/pubnub-10.3.0.tar.gz
97+
package-name: pubnub-10.4.0
98+
location: https://github.com/pubnub/python/releases/download/10.4.0/pubnub-10.4.0.tar.gz
9699
supported-platforms:
97100
supported-operating-systems:
98101
Linux:
99102
runtime-version:
100-
- Python 3.7
101-
- Python 3.8
102103
- Python 3.9
103104
- Python 3.10
105+
- Python 3.11
106+
- Python 3.12
107+
- Python 3.13
104108
minimum-os-version:
105109
- Ubuntu 12.04
106110
maximum-os-version:
@@ -110,10 +114,11 @@ sdks:
110114
- x86-64
111115
macOS:
112116
runtime-version:
113-
- Python 3.7
114-
- Python 3.8
115117
- Python 3.9
116118
- Python 3.10
119+
- Python 3.11
120+
- Python 3.12
121+
- Python 3.13
117122
minimum-os-version:
118123
- macOS 10.12
119124
maximum-os-version:
@@ -122,10 +127,11 @@ sdks:
122127
- x86-64
123128
Windows:
124129
runtime-version:
125-
- Python 3.7
126-
- Python 3.8
127130
- Python 3.9
128131
- Python 3.10
132+
- Python 3.11
133+
- Python 3.12
134+
- Python 3.13
129135
minimum-os-version:
130136
- Windows Vista Ultimate
131137
maximum-os-version:
@@ -163,6 +169,11 @@ sdks:
163169
license-url: https://github.com/encode/httpx/blob/master/LICENSE.md
164170
is-required: Required
165171
changelog:
172+
- date: 2025-05-07
173+
version: 10.4.0
174+
changes:
175+
- type: feature
176+
text: "Added pagination to List Files."
166177
- date: 2025-04-10
167178
version: 10.3.0
168179
changes:
@@ -772,19 +783,6 @@ supported-platforms:
772783
- python 3.5.2
773784
- python 3.6.0
774785
- pypy
775-
-
776-
version: PubNub Python Tornado SDK
777-
platforms:
778-
- FreeBSD 8-STABLE or later, amd64, 386
779-
- Linux 2.6 or later, amd64, 386.
780-
- Mac OS X 10.8 or later, amd64
781-
- Windows 7 or later, amd64, 386
782-
editors:
783-
- python 2.7.13
784-
- python 3.4.5
785-
- python 3.5.2
786-
- python 3.6.0
787-
- pypy
788786
-
789787
version: PubNub Python Asyncio SDK
790788
platforms:
@@ -793,12 +791,9 @@ supported-platforms:
793791
- Mac OS X 10.8 or later, amd64
794792
- Windows 7 or later, amd64, 386
795793
editors:
796-
- python 3.4.5
797-
- python 3.5.2
798-
- python 3.6.0
799-
-
800-
version: PubNub Python Twisted SDK
801-
platforms:
802-
- Linux 2.6 or later, amd64, 386.
803-
editors:
804-
- python 2.7.13
794+
- python 3.9.21
795+
- python 3.10.16
796+
- python 3.11.11
797+
- python 3.12.9
798+
- python 3.13.2
799+

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## 10.4.0
2+
May 07 2025
3+
4+
#### Added
5+
- Added pagination to List Files.
6+
17
## 10.3.0
28
April 10 2025
39

pubnub/endpoints/entities/endpoint.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -164,12 +164,13 @@ def spaces(self, spaces):
164164
class ListEndpoint:
165165
__metaclass__ = ABCMeta
166166

167-
def __init__(self):
168-
self._limit = None
169-
self._filter = None
170-
self._include_total_count = None
171-
self._sort_keys = None
172-
self._page = None
167+
def __init__(self, limit: int = None, filter: str = None, include_total_count: bool = None,
168+
sort_keys: list = None, page: str = None):
169+
self._limit = limit
170+
self._filter = filter
171+
self._include_total_count = include_total_count
172+
self._sort_keys = sort_keys
173+
self._page = page
173174

174175
def limit(self, limit):
175176
self._limit = int(limit)

pubnub/endpoints/file_operations/list_files.py

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,26 +14,43 @@ class PNGetFilesResultEnvelope(Envelope):
1414
class ListFiles(FileOperationEndpoint):
1515
LIST_FILES_URL = "/v1/files/%s/channels/%s/files"
1616
_channel: str
17+
_limit: int
18+
_next: str
1719

18-
def __init__(self, pubnub, channel: str = None):
20+
def __init__(self, pubnub, channel: str = None, *, limit: int = None, next: str = None):
1921
FileOperationEndpoint.__init__(self, pubnub)
2022
self._channel = channel
23+
self._limit = limit
24+
self._next = next
2125

2226
def build_path(self):
2327
return ListFiles.LIST_FILES_URL % (
2428
self.pubnub.config.subscribe_key,
2529
utils.url_encode(self._channel)
2630
)
2731

28-
def channel(self, channel) -> 'ListFiles':
32+
def channel(self, channel: str) -> 'ListFiles':
2933
self._channel = channel
3034
return self
3135

36+
def limit(self, limit: int) -> 'ListFiles':
37+
self._limit = limit
38+
return self
39+
40+
def next(self, next: str) -> 'ListFiles':
41+
self._next = next
42+
return self
43+
3244
def http_method(self):
3345
return HttpMethod.GET
3446

3547
def custom_params(self):
36-
return {}
48+
params = {}
49+
if self._limit:
50+
params["limit"] = str(self._limit)
51+
if self._next:
52+
params["next"] = str(self._next)
53+
return params
3754

3855
def is_auth_required(self):
3956
return True

pubnub/models/consumer/file.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ def __init__(self, result):
33
self.data = result['data']
44
self.count = result.get('count', None)
55
self.next = result.get('next', None)
6-
self.prev = result.get('prev', None)
76

87
def __str__(self):
98
return "Get files success with data: %s" % self.data

pubnub/pubnub_core.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@
9696

9797
class PubNubCore:
9898
"""A base class for PubNub Python API implementations"""
99-
SDK_VERSION = "10.3.0"
99+
SDK_VERSION = "10.4.0"
100100
SDK_NAME = "PubNub-Python"
101101

102102
TIMESTAMP_DIVIDER = 1000
@@ -466,8 +466,8 @@ def download_file(self):
466466
else:
467467
raise NotImplementedError
468468

469-
def list_files(self, channel: str = None) -> ListFiles:
470-
return ListFiles(self, channel=channel)
469+
def list_files(self, channel: str = None, *, limit: int = None, next: str = None) -> ListFiles:
470+
return ListFiles(self, channel=channel, limit=limit, next=next)
471471

472472
def get_file_url(self, channel: str = None, file_name: str = None, file_id: str = None) -> GetFileDownloadUrl:
473473
return GetFileDownloadUrl(self, channel=channel, file_name=file_name, file_id=file_id)

setup.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
setup(
44
name='pubnub',
5-
version='10.3.0',
5+
version='10.4.0',
66
description='PubNub Real-time push service in the cloud',
77
author='PubNub',
88
author_email='[email protected]',

tests/integrational/asyncio/test_file_upload.py

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,87 @@ async def test_delete_file(file_for_upload):
5757
filter_query_parameters=['uuid', 'l_file', 'pnsdk']
5858
)
5959
@pytest.mark.asyncio(loop_scope="module")
60-
async def test_list_files():
60+
async def test_list_files(file_for_upload, file_upload_test_data):
6161
pubnub = PubNubAsyncio(pnconf_env_copy())
62+
pubnub.config.uuid = "files_asyncio_uuid"
63+
64+
# Clear existing files first to ensure a clean state
65+
envelope = await pubnub.list_files().channel(CHANNEL).future()
66+
files = envelope.result.data
67+
for i in range(len(files)):
68+
file = files[i]
69+
await pubnub.delete_file().channel(CHANNEL).file_id(file["id"]).file_name(file["name"]).future()
70+
71+
envelope = await send_file(pubnub, file_for_upload)
72+
73+
envelope = await pubnub.list_files().channel(CHANNEL).future()
74+
75+
assert isinstance(envelope.result, PNGetFilesResult)
76+
assert envelope.result.count == 1
77+
assert file_upload_test_data["UPLOADED_FILENAME"] == envelope.result.data[0]["name"]
78+
await pubnub.stop()
79+
80+
81+
@pn_vcr.use_cassette(
82+
"tests/integrational/fixtures/asyncio/file_upload/list_files_with_limit.json", serializer="pn_json",
83+
filter_query_parameters=['uuid', 'l_file', 'pnsdk']
84+
)
85+
@pytest.mark.asyncio(loop_scope="module")
86+
async def test_list_files_with_limit(file_for_upload, file_upload_test_data):
87+
pubnub = PubNubAsyncio(pnconf_env_copy())
88+
pubnub.config.uuid = "files_asyncio_uuid"
89+
await send_file(pubnub, file_for_upload)
90+
await send_file(pubnub, file_for_upload)
91+
envelope = await pubnub.list_files().channel(CHANNEL).limit(2).future()
92+
assert isinstance(envelope.result, PNGetFilesResult)
93+
assert envelope.result.count == 2
94+
assert file_upload_test_data["UPLOADED_FILENAME"] == envelope.result.data[0]["name"]
95+
await pubnub.stop()
96+
97+
98+
@pn_vcr.use_cassette(
99+
"tests/integrational/fixtures/asyncio/file_upload/list_files_with_page.json", serializer="pn_json",
100+
filter_query_parameters=['uuid', 'l_file', 'pnsdk']
101+
)
102+
@pytest.mark.asyncio(loop_scope="module")
103+
async def test_list_files_with_page(file_for_upload, file_upload_test_data):
104+
pubnub = PubNubAsyncio(pnconf_env_copy())
105+
pubnub.config.uuid = "files_asyncio_uuid"
106+
await send_file(pubnub, file_for_upload)
107+
await send_file(pubnub, file_for_upload)
108+
envelope = await pubnub.list_files().channel(CHANNEL).limit(2).future()
109+
assert isinstance(envelope.result, PNGetFilesResult)
110+
assert envelope.result.count == 2
111+
assert envelope.result.next is not None
112+
next_page = envelope.result.next
113+
file_ids = [envelope.result.data[0]['id'], envelope.result.data[1]['id']]
114+
envelope = await pubnub.list_files().channel(CHANNEL).limit(2).next(next_page).future()
115+
assert isinstance(envelope.result, PNGetFilesResult)
116+
assert envelope.result.count == 2
117+
assert envelope.result.next is not None
118+
assert envelope.result.data[0]['id'] not in file_ids
119+
assert envelope.result.data[1]['id'] not in file_ids
120+
assert file_upload_test_data["UPLOADED_FILENAME"] == envelope.result.data[0]["name"]
121+
await pubnub.stop()
122+
123+
124+
# @pn_vcr.use_cassette( # Needs new recording for asyncio
125+
# "tests/integrational/fixtures/asyncio/file_upload/delete_all_files.json", serializer="pn_json",
126+
# filter_query_parameters=['uuid', 'l_file', 'pnsdk']
127+
# )
128+
@pytest.mark.asyncio(loop_scope="module")
129+
async def test_delete_all_files():
130+
pubnub = PubNubAsyncio(pnconf_env_copy())
131+
pubnub.config.uuid = "files_asyncio_uuid"
132+
envelope = await pubnub.list_files().channel(CHANNEL).future()
133+
files = envelope.result.data
134+
for i in range(len(files)):
135+
file = files[i]
136+
await pubnub.delete_file().channel(CHANNEL).file_id(file["id"]).file_name(file["name"]).future()
62137
envelope = await pubnub.list_files().channel(CHANNEL).future()
63138

64139
assert isinstance(envelope.result, PNGetFilesResult)
65-
assert envelope.result.count == 7
140+
assert envelope.result.count == 0
66141
await pubnub.stop()
67142

68143

0 commit comments

Comments
 (0)