nc-py-api 0.19.1__tar.gz → 0.20.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/CHANGELOG.md +16 -0
  2. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/PKG-INFO +1 -1
  3. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_session.py +8 -2
  4. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_version.py +1 -1
  5. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/nextcloud.py +8 -9
  6. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/webhooks.py +13 -6
  7. nc_py_api-0.19.1/nc_py_api/ex_app/events_listener.py +0 -137
  8. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/.gitignore +0 -0
  9. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/AUTHORS +0 -0
  10. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/LICENSE.txt +0 -0
  11. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/README.md +0 -0
  12. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/__init__.py +0 -0
  13. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_deffered_error.py +0 -0
  14. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_exceptions.py +0 -0
  15. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_misc.py +0 -0
  16. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_preferences.py +0 -0
  17. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_preferences_ex.py +0 -0
  18. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_talk_api.py +0 -0
  19. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/_theming.py +0 -0
  20. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/activity.py +0 -0
  21. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/apps.py +0 -0
  22. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/calendar_api.py +0 -0
  23. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/__init__.py +0 -0
  24. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/defs.py +0 -0
  25. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/integration_fastapi.py +0 -0
  26. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/logger.py +0 -0
  27. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/misc.py +0 -0
  28. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/occ_commands.py +0 -0
  29. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/persist_transformers_cache.py +0 -0
  30. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/providers/__init__.py +0 -0
  31. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/providers/providers.py +0 -0
  32. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/providers/task_processing.py +0 -0
  33. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/__init__.py +0 -0
  34. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/files_actions.py +0 -0
  35. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/resources.py +0 -0
  36. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/settings.py +0 -0
  37. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/top_menu.py +0 -0
  38. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/ui/ui.py +0 -0
  39. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/ex_app/uvicorn_fastapi.py +0 -0
  40. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/files/__init__.py +0 -0
  41. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/files/_files.py +0 -0
  42. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/files/files.py +0 -0
  43. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/files/files_async.py +0 -0
  44. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/files/sharing.py +0 -0
  45. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/loginflow_v2.py +0 -0
  46. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/notes.py +0 -0
  47. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/notifications.py +0 -0
  48. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/options.py +0 -0
  49. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/talk.py +0 -0
  50. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/talk_bot.py +0 -0
  51. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/user_status.py +0 -0
  52. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/users.py +0 -0
  53. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/users_groups.py +0 -0
  54. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/nc_py_api/weather_status.py +0 -0
  55. {nc_py_api-0.19.1 → nc_py_api-0.20.0}/pyproject.toml +0 -0
@@ -2,6 +2,22 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.20.0 - 2025-04-28]
6
+
7
+ ### Changed
8
+
9
+ - ExApps: `nc_py_api.ex_app.events_listener.EventsListener` was removed in favor of `nc_py_api.webhooks`. #348
10
+
11
+ ### Fixed
12
+
13
+ - Method `download2stream` not working correctly when Nextcloud returns compressed content. #352 Thanks to @PatrickPromitzer for reporting this.
14
+
15
+ ## [0.19.2 - 2025-03-17]
16
+
17
+ ### Added
18
+
19
+ - Optional `response_type` parameter of `nextcloud.ocs` method for calling OCS endpoints that return raw data. #341 Thanks to @janepie
20
+
5
21
  ## [0.19.1 - 2025-03-07]
6
22
 
7
23
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nc-py-api
3
- Version: 0.19.1
3
+ Version: 0.20.0
4
4
  Summary: Nextcloud Python Framework
5
5
  Project-URL: Changelog, https://github.com/cloud-py-api/nc_py_api/blob/main/CHANGELOG.md
6
6
  Project-URL: Documentation, https://cloud-py-api.github.io/nc_py_api/
@@ -197,6 +197,7 @@ class NcSessionBasic(NcSessionBase, ABC):
197
197
  *,
198
198
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
199
199
  json: dict | list | None = None,
200
+ response_type: str | None = None,
200
201
  params: dict | None = None,
201
202
  files: dict | None = None,
202
203
  **kwargs,
@@ -215,6 +216,8 @@ class NcSessionBasic(NcSessionBase, ABC):
215
216
  if response.status_code == 204: # NO_CONTENT
216
217
  return []
217
218
  response_data = loads(response.text)
219
+ if response_type == "json":
220
+ return response_data
218
221
  ocs_meta = response_data["ocs"]["meta"]
219
222
  if ocs_meta["status"] != "ok":
220
223
  if (
@@ -304,7 +307,7 @@ class NcSessionBasic(NcSessionBase, ABC):
304
307
  adapter = self.adapter_dav if dav else self.adapter
305
308
  with adapter.stream("GET", url_path, params=params, headers=kwargs.get("headers")) as response:
306
309
  check_error(response)
307
- for data_chunk in response.iter_raw(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
310
+ for data_chunk in response.iter_bytes(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
308
311
  fp.write(data_chunk)
309
312
 
310
313
 
@@ -319,6 +322,7 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
319
322
  *,
320
323
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
321
324
  json: dict | list | None = None,
325
+ response_type: str | None = None,
322
326
  params: dict | None = None,
323
327
  files: dict | None = None,
324
328
  **kwargs,
@@ -337,6 +341,8 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
337
341
  if response.status_code == 204: # NO_CONTENT
338
342
  return []
339
343
  response_data = loads(response.text)
344
+ if response_type == "json":
345
+ return response_data
340
346
  ocs_meta = response_data["ocs"]["meta"]
341
347
  if ocs_meta["status"] != "ok":
342
348
  if (
@@ -428,7 +434,7 @@ class AsyncNcSessionBasic(NcSessionBase, ABC):
428
434
  adapter = self.adapter_dav if dav else self.adapter
429
435
  async with adapter.stream("GET", url_path, params=params, headers=kwargs.get("headers")) as response:
430
436
  check_error(response)
431
- async for data_chunk in response.aiter_raw(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
437
+ async for data_chunk in response.aiter_bytes(chunk_size=kwargs.get("chunk_size", 5 * 1024 * 1024)):
432
438
  fp.write(data_chunk)
433
439
 
434
440
 
@@ -1,3 +1,3 @@
1
1
  """Version of nc_py_api."""
2
2
 
3
- __version__ = "0.19.1"
3
+ __version__ = "0.20.0"
@@ -31,7 +31,6 @@ from .activity import _ActivityAPI, _AsyncActivityAPI
31
31
  from .apps import _AppsAPI, _AsyncAppsAPI
32
32
  from .calendar_api import _CalendarAPI
33
33
  from .ex_app.defs import LogLvl
34
- from .ex_app.events_listener import AsyncEventsListenerAPI, EventsListenerAPI
35
34
  from .ex_app.occ_commands import AsyncOccCommandsAPI, OccCommandsAPI
36
35
  from .ex_app.providers.providers import AsyncProvidersApi, ProvidersApi
37
36
  from .ex_app.ui.ui import AsyncUiApi, UiApi
@@ -137,11 +136,14 @@ class _NextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
137
136
  *,
138
137
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
139
138
  json: dict | list | None = None,
139
+ response_type: str | None = None,
140
140
  params: dict | None = None,
141
141
  **kwargs,
142
142
  ):
143
143
  """Performs OCS call and returns OCS response payload data."""
144
- return self._session.ocs(method, path, content=content, json=json, params=params, **kwargs)
144
+ return self._session.ocs(
145
+ method, path, content=content, json=json, response_type=response_type, params=params, **kwargs
146
+ )
145
147
 
146
148
  def download_log(self, fp) -> None:
147
149
  """Downloads Nextcloud log file. Requires Admin privileges."""
@@ -238,11 +240,14 @@ class _AsyncNextcloudBasic(ABC): # pylint: disable=too-many-instance-attributes
238
240
  *,
239
241
  content: bytes | str | typing.Iterable[bytes] | typing.AsyncIterable[bytes] | None = None,
240
242
  json: dict | list | None = None,
243
+ response_type: str | None = None,
241
244
  params: dict | None = None,
242
245
  **kwargs,
243
246
  ):
244
247
  """Performs OCS call and returns OCS response payload data."""
245
- return await self._session.ocs(method, path, content=content, json=json, params=params, **kwargs)
248
+ return await self._session.ocs(
249
+ method, path, content=content, json=json, response_type=response_type, params=params, **kwargs
250
+ )
246
251
 
247
252
  async def download_log(self, fp) -> None:
248
253
  """Downloads Nextcloud log file. Requires Admin privileges."""
@@ -321,8 +326,6 @@ class NextcloudApp(_NextcloudBasic):
321
326
  ui: UiApi
322
327
  """Nextcloud UI API for ExApps"""
323
328
  providers: ProvidersApi
324
- """API for registering providers for Nextcloud"""
325
- events_listener: EventsListenerAPI
326
329
  """API for registering Events listeners for ExApps"""
327
330
  occ_commands: OccCommandsAPI
328
331
  """API for registering OCC command for ExApps"""
@@ -338,7 +341,6 @@ class NextcloudApp(_NextcloudBasic):
338
341
  self.preferences_ex = PreferencesExAPI(self._session)
339
342
  self.ui = UiApi(self._session)
340
343
  self.providers = ProvidersApi(self._session)
341
- self.events_listener = EventsListenerAPI(self._session)
342
344
  self.occ_commands = OccCommandsAPI(self._session)
343
345
 
344
346
  @property
@@ -456,8 +458,6 @@ class AsyncNextcloudApp(_AsyncNextcloudBasic):
456
458
  ui: AsyncUiApi
457
459
  """Nextcloud UI API for ExApps"""
458
460
  providers: AsyncProvidersApi
459
- """API for registering providers for Nextcloud"""
460
- events_listener: AsyncEventsListenerAPI
461
461
  """API for registering Events listeners for ExApps"""
462
462
  occ_commands: AsyncOccCommandsAPI
463
463
  """API for registering OCC command for ExApps"""
@@ -473,7 +473,6 @@ class AsyncNextcloudApp(_AsyncNextcloudBasic):
473
473
  self.preferences_ex = AsyncPreferencesExAPI(self._session)
474
474
  self.ui = AsyncUiApi(self._session)
475
475
  self.providers = AsyncProvidersApi(self._session)
476
- self.events_listener = AsyncEventsListenerAPI(self._session)
477
476
  self.occ_commands = AsyncOccCommandsAPI(self._session)
478
477
 
479
478
  @property
@@ -2,6 +2,7 @@
2
2
 
3
3
  import dataclasses
4
4
 
5
+ from ._exceptions import NextcloudExceptionNotFound
5
6
  from ._misc import clear_from_params_empty # , require_capabilities
6
7
  from ._session import AppConfig, AsyncNcSessionBasic, NcSessionBasic
7
8
 
@@ -51,7 +52,7 @@ class WebhookInfo:
51
52
  @property
52
53
  def user_id_filter(self) -> str:
53
54
  """Currently unknown."""
54
- return self._raw_data["userIdFilter"]
55
+ return "" if self._raw_data["userIdFilter"] is None else self._raw_data["userIdFilter"]
55
56
 
56
57
  @property
57
58
  def headers(self) -> dict:
@@ -84,8 +85,11 @@ class _WebhooksAPI:
84
85
  params = {"uri": uri_filter} if uri_filter else {}
85
86
  return [WebhookInfo(i) for i in self._session.ocs("GET", f"{self._ep_base}", params=params)]
86
87
 
87
- def get_entry(self, webhook_id: int) -> WebhookInfo:
88
- return WebhookInfo(self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
88
+ def get_entry(self, webhook_id: int) -> WebhookInfo | None:
89
+ try:
90
+ return WebhookInfo(self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
91
+ except NextcloudExceptionNotFound:
92
+ return None
89
93
 
90
94
  def register(
91
95
  self,
@@ -151,7 +155,7 @@ class _WebhooksAPI:
151
155
  class _AsyncWebhooksAPI:
152
156
  """The class provides the async application management API on the Nextcloud server."""
153
157
 
154
- _ep_base: str = "/ocs/v1.php/webhooks"
158
+ _ep_base: str = "/ocs/v1.php/apps/webhook_listeners/api/v1/webhooks"
155
159
 
156
160
  def __init__(self, session: AsyncNcSessionBasic):
157
161
  self._session = session
@@ -160,8 +164,11 @@ class _AsyncWebhooksAPI:
160
164
  params = {"uri": uri_filter} if uri_filter else {}
161
165
  return [WebhookInfo(i) for i in await self._session.ocs("GET", f"{self._ep_base}", params=params)]
162
166
 
163
- async def get_entry(self, webhook_id: int) -> WebhookInfo:
164
- return WebhookInfo(await self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
167
+ async def get_entry(self, webhook_id: int) -> WebhookInfo | None:
168
+ try:
169
+ return WebhookInfo(await self._session.ocs("GET", f"{self._ep_base}/{webhook_id}"))
170
+ except NextcloudExceptionNotFound:
171
+ return None
165
172
 
166
173
  async def register(
167
174
  self,
@@ -1,137 +0,0 @@
1
- """Nextcloud API for registering Events listeners for ExApps."""
2
-
3
- import dataclasses
4
-
5
- from .._exceptions import NextcloudExceptionNotFound
6
- from .._misc import require_capabilities
7
- from .._session import AsyncNcSessionApp, NcSessionApp
8
-
9
- _EP_SUFFIX: str = "events_listener"
10
-
11
-
12
- @dataclasses.dataclass
13
- class EventsListener:
14
- """EventsListener description."""
15
-
16
- def __init__(self, raw_data: dict):
17
- self._raw_data = raw_data
18
-
19
- @property
20
- def event_type(self) -> str:
21
- """Main type of event, e.g. ``node_event``."""
22
- return self._raw_data["event_type"]
23
-
24
- @property
25
- def event_subtypes(self) -> str:
26
- """Subtypes for which fire event, e.g. ``NodeCreatedEvent``, ``NodeDeletedEvent``."""
27
- return self._raw_data["event_subtypes"]
28
-
29
- @property
30
- def action_handler(self) -> str:
31
- """Relative ExApp url which will be called by Nextcloud."""
32
- return self._raw_data["action_handler"]
33
-
34
- def __repr__(self):
35
- return f"<{self.__class__.__name__} event_type={self.event_type}, handler={self.action_handler}>"
36
-
37
-
38
- class EventsListenerAPI:
39
- """API for registering Events listeners, avalaible as **nc.events_handler.<method>**."""
40
-
41
- def __init__(self, session: NcSessionApp):
42
- self._session = session
43
-
44
- def register(
45
- self,
46
- event_type: str,
47
- callback_url: str,
48
- event_subtypes: list[str] | None = None,
49
- ) -> None:
50
- """Registers or edits the events listener."""
51
- if event_subtypes is None:
52
- event_subtypes = []
53
- require_capabilities("app_api", self._session.capabilities)
54
- params = {
55
- "eventType": event_type,
56
- "actionHandler": callback_url,
57
- "eventSubtypes": event_subtypes,
58
- }
59
- self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
60
-
61
- def unregister(self, event_type: str, not_fail=True) -> None:
62
- """Removes the events listener."""
63
- require_capabilities("app_api", self._session.capabilities)
64
- try:
65
- self._session.ocs(
66
- "DELETE",
67
- f"{self._session.ae_url}/{_EP_SUFFIX}",
68
- params={"eventType": event_type},
69
- )
70
- except NextcloudExceptionNotFound as e:
71
- if not not_fail:
72
- raise e from None
73
-
74
- def get_entry(self, event_type: str) -> EventsListener | None:
75
- """Get information about the event listener."""
76
- require_capabilities("app_api", self._session.capabilities)
77
- try:
78
- return EventsListener(
79
- self._session.ocs(
80
- "GET",
81
- f"{self._session.ae_url}/{_EP_SUFFIX}",
82
- params={"eventType": event_type},
83
- )
84
- )
85
- except NextcloudExceptionNotFound:
86
- return None
87
-
88
-
89
- class AsyncEventsListenerAPI:
90
- """API for registering Events listeners, avalaible as **nc.events_handler.<method>**."""
91
-
92
- def __init__(self, session: AsyncNcSessionApp):
93
- self._session = session
94
-
95
- async def register(
96
- self,
97
- event_type: str,
98
- callback_url: str,
99
- event_subtypes: list[str] | None = None,
100
- ) -> None:
101
- """Registers or edits the events listener."""
102
- if event_subtypes is None:
103
- event_subtypes = []
104
- require_capabilities("app_api", await self._session.capabilities)
105
- params = {
106
- "eventType": event_type,
107
- "actionHandler": callback_url,
108
- "eventSubtypes": event_subtypes,
109
- }
110
- await self._session.ocs("POST", f"{self._session.ae_url}/{_EP_SUFFIX}", json=params)
111
-
112
- async def unregister(self, event_type: str, not_fail=True) -> None:
113
- """Removes the events listener."""
114
- require_capabilities("app_api", await self._session.capabilities)
115
- try:
116
- await self._session.ocs(
117
- "DELETE",
118
- f"{self._session.ae_url}/{_EP_SUFFIX}",
119
- params={"eventType": event_type},
120
- )
121
- except NextcloudExceptionNotFound as e:
122
- if not not_fail:
123
- raise e from None
124
-
125
- async def get_entry(self, event_type: str) -> EventsListener | None:
126
- """Get information about the event listener."""
127
- require_capabilities("app_api", await self._session.capabilities)
128
- try:
129
- return EventsListener(
130
- await self._session.ocs(
131
- "GET",
132
- f"{self._session.ae_url}/{_EP_SUFFIX}",
133
- params={"eventType": event_type},
134
- )
135
- )
136
- except NextcloudExceptionNotFound:
137
- return None
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes