Skip to content

__repr__ method #147

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

Merged
merged 2 commits into from
Oct 14, 2023
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
9 changes: 7 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@ All notable changes to this project will be documented in this file.
## [0.4.0 - 2023-10-2x]

As the project moves closer to `beta`, final unification changes are being made.
This release contains some breaking changes in `users` API.
This release contains some breaking changes in `users`, `notifications` API.

### Added

- `__repr__` method added for most objects(previously it was only present for `FsNode`).

### Changed

- `users.get_details` renamed to `get_user` and returns a class instead of a dictionary. #145
- Optional argument `displayname` in `users.create` renamed to `display_name`.
- The `apps.ExAppInfo` class has been rewritten in the same format as all the others.
- The `apps.ExAppInfo` class has been rewritten in the same format as all the others. #146
- `notifications.Notification` class has been rewritten in the same format as all the others.

### Fixed

Expand Down
3 changes: 0 additions & 3 deletions docs/reference/Users/Notifications.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,3 @@ Notifications

.. autoclass:: nc_py_api.notifications.Notification
:members:

.. autoclass:: nc_py_api.notifications.NotificationInfo
:members:
11 changes: 10 additions & 1 deletion nc_py_api/activity.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ def priority(self) -> int:
"""Arrangement priority in ascending order. Values from 0 to 99."""
return self._raw_data["priority"]

def __repr__(self):
return f"<{self.__class__.__name__} id={self.filter_id}, name={self.name}, priority={self.priority}>"


@dataclasses.dataclass
class Activity:
Expand Down Expand Up @@ -122,10 +125,16 @@ def icon(self) -> str:
return self._raw_data["icon"]

@property
def activity_time(self) -> datetime.datetime:
def time(self) -> datetime.datetime:
"""Time when the activity occurred."""
return nc_iso_time_to_datetime(self._raw_data["datetime"])

def __repr__(self):
return (
f"<{self.__class__.__name__} id={self.activity_id}, app={self.app}, type={self.activity_type},"
f" time={self.time}>"
)


class _ActivityAPI:
"""The class provides the Activity Application API."""
Expand Down
3 changes: 3 additions & 0 deletions nc_py_api/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ def system(self) -> bool:
"""Flag indicating if the application is a system application."""
return bool(self._raw_data["system"])

def __repr__(self):
return f"<{self.__class__.__name__} id={self.app_id}, ver={self.version}>"


class _AppsAPI:
"""The class provides the application management API on the Nextcloud server."""
Expand Down
3 changes: 3 additions & 0 deletions nc_py_api/files/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,9 @@ def user_assignable(self) -> bool:
"""Flag indicating if User can assign this Tag."""
return bool(self._raw_data.get("oc:user-assignable", "false").lower() == "true")

def __repr__(self):
return f"<{self.__class__.__name__} id={self.tag_id}, name={self.display_name}>"


class ShareType(enum.IntEnum):
"""Type of the object that will receive share."""
Expand Down
3 changes: 3 additions & 0 deletions nc_py_api/notes.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ def last_modified(self) -> datetime.datetime:
modified = self._raw_data.get("modified", 0)
return datetime.datetime.utcfromtimestamp(modified).replace(tzinfo=datetime.timezone.utc)

def __repr__(self):
return f"<{self.__class__.__name__} id={self.note_id}, title={self.title}, last_modified={self.last_modified}>"


class NotesSettings(typing.TypedDict):
"""Settings of Notes App."""
Expand Down
101 changes: 58 additions & 43 deletions nc_py_api/notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,53 +13,68 @@
from ._session import NcSessionApp, NcSessionBasic


@dataclasses.dataclass
class NotificationInfo:
"""Extra Notification attributes from Nextcloud."""

app_name: str
"""Application name that generated notification."""
user_id: str
"""User name for which this notification is."""
time: datetime.datetime
"""Time when the notification was created."""
subject: str
"""Subject of the notification."""
message: str
"""Message of the notification."""
link: str
"""Link which will be opened when user clicks on notification."""
icon: str
"""Relative to instance url of the icon image."""

def __init__(self, raw_info: dict):
self.app_name = raw_info["app"]
self.user_id = raw_info["user"]
self.time = nc_iso_time_to_datetime(raw_info["datetime"])
self.subject = raw_info["subject"]
self.message = raw_info["message"]
self.link = raw_info.get("link", "")
self.icon = raw_info.get("icon", "")


@dataclasses.dataclass
class Notification:
"""Class representing information about Nextcloud notification."""

notification_id: int
"""ID of the notification."""
object_id: str
"""Randomly generated unique object ID"""
object_type: str
"""Currently not used."""
info: NotificationInfo
"""Additional extra information for the object"""

def __init__(self, raw_info: dict):
self.notification_id = raw_info["notification_id"]
self.object_id = raw_info["object_id"]
self.object_type = raw_info["object_type"]
self.info = NotificationInfo(raw_info)
def __init__(self, raw_data: dict):
self._raw_data = raw_data

@property
def notification_id(self) -> int:
"""ID of the notification."""
return self._raw_data["notification_id"]

@property
def object_id(self) -> str:
"""Randomly generated unique object ID."""
return self._raw_data["object_id"]

@property
def object_type(self) -> str:
"""Currently not used."""
return self._raw_data["object_type"]

@property
def app_name(self) -> str:
"""Application name that generated notification."""
return self._raw_data["app"]

@property
def user_id(self) -> str:
"""User ID of user for which this notification is."""
return self._raw_data["user"]

@property
def subject(self) -> str:
"""Subject of the notification."""
return self._raw_data["subject"]

@property
def message(self) -> str:
"""Message of the notification."""
return self._raw_data["message"]

@property
def time(self) -> datetime.datetime:
"""Time when the notification was created."""
return nc_iso_time_to_datetime(self._raw_data["datetime"])

@property
def link(self) -> str:
"""Link, which will be opened when user clicks on notification."""
return self._raw_data.get("link", "")

@property
def icon(self) -> str:
"""Relative to instance url of the icon image."""
return self._raw_data.get("icon", "")

def __repr__(self):
return (
f"<{self.__class__.__name__} id={self.notification_id}, app_name={self.app_name}, user_id={self.user_id},"
f" time={self.time}>"
)


class _NotificationsAPI:
Expand Down
29 changes: 28 additions & 1 deletion nc_py_api/talk.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Nextcloud Talk API definitions."""

import dataclasses
import datetime
import enum
import os
import typing
Expand Down Expand Up @@ -280,6 +281,12 @@ def markdown(self) -> bool:
"""Whether the message should be rendered as markdown or shown as plain text."""
return self._raw_data.get("markdown", False)

def __repr__(self):
return (
f"<{self.__class__.__name__} id={self.message_id}, author={self.actor_display_name},"
f" time={datetime.datetime.utcfromtimestamp(self.timestamp).replace(tzinfo=datetime.timezone.utc)}>"
)


class TalkFileMessage(TalkMessage):
"""Subclass of Talk Message representing message-containing file."""
Expand Down Expand Up @@ -625,6 +632,12 @@ def status_clear_at(self) -> typing.Optional[int]:
"""
return self._raw_data.get("statusClearAt", None)

def __repr__(self):
return (
f"<{self.__class__.__name__} id={self.conversation_id}, name={self.display_name},"
f" type={self.conversation_type.name}>"
)


@dataclasses.dataclass(init=False)
class Participant(_TalkUserStatus):
Expand Down Expand Up @@ -657,7 +670,7 @@ def participant_type(self) -> ParticipantType:

@property
def last_ping(self) -> int:
"""Timestamp of the last ping. Should be used for sorting."""
"""Timestamp of the last ping. Should be used for sorting."""
return self._raw_data["lastPing"]

@property
Expand Down Expand Up @@ -685,6 +698,11 @@ def breakout_token(self) -> str:
"""Only available with breakout-rooms-v1 capability."""
return self._raw_data.get("roomToken", "")

def __repr__(self):
return (
f"<{self.__class__.__name__} id={self.attendee_id}, name={self.display_name}, last_ping={self.last_ping}>"
)


@dataclasses.dataclass
class BotInfoBasic:
Expand Down Expand Up @@ -713,6 +731,9 @@ def state(self) -> int:
"""One of the Bot states: ``0`` - Disabled, ``1`` - enabled, ``2`` - **No setup**."""
return self._raw_data["state"]

def __repr__(self):
return f"<{self.__class__.__name__} id={self.bot_id}, name={self.bot_name}>"


@dataclasses.dataclass(init=False)
class BotInfo(BotInfoBasic):
Expand Down Expand Up @@ -771,6 +792,9 @@ def option(self) -> int:
"""The option that was voted for."""
return self._raw_data["optionId"]

def __repr__(self):
return f"<{self.__class__.__name__} actor={self.actor_display_name}, voted_for={self.option}>"


@dataclasses.dataclass
class Poll:
Expand Down Expand Up @@ -856,3 +880,6 @@ def num_voters(self) -> int:
def details(self) -> list[PollDetail]:
"""Detailed list who voted for which option (only available for public closed polls)."""
return [PollDetail(i) for i in self._raw_data.get("details", [])]

def __repr__(self):
return f"<{self.__class__.__name__} id={self.poll_id}, author={self.actor_display_name}>"
3 changes: 3 additions & 0 deletions nc_py_api/talk_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def conversation_name(self) -> str:
"""The name of the conversation in which the message was posted."""
return self._raw_data["target"]["name"]

def __repr__(self):
return f"<{self.__class__.__name__} conversation={self.conversation_name}, actor={self.actor_display_name}>"


class TalkBot:
"""A class that implements the TalkBot functionality."""
Expand Down
9 changes: 9 additions & 0 deletions nc_py_api/user_status.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ def status_type(self) -> str:
"""Status type, on of the: online, away, dnd, invisible, offline."""
return self._raw_data.get("status", "")

def __repr__(self):
return f"<{self.__class__.__name__} user_id={self.user_id}, status_type={self.status_type}>"


@dataclasses.dataclass(init=False)
class CurrentUserStatus(UserStatus):
Expand All @@ -97,6 +100,12 @@ def status_type_defined(self) -> bool:
"""*True* if :py:attr:`UserStatus.status_type` is set by user, *False* otherwise."""
return self._raw_data["statusIsUserDefined"]

def __repr__(self):
return (
f"<{self.__class__.__name__} user_id={self.user_id}, status_type={self.status_type},"
f" status_id={self.status_id}>"
)


class _UserStatusAPI:
"""Class providing the user status management API on the Nextcloud server."""
Expand Down
3 changes: 3 additions & 0 deletions nc_py_api/users.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,9 @@ def backend_capabilities(self) -> dict:
"""By default, only the ``setDisplayName`` and ``setPassword`` keys are available."""
return self._raw_data["backendCapabilities"]

def __repr__(self):
return f"<{self.__class__.__name__} id={self.user_id}, backend={self.backend}, last_login={self.last_login}>"


class _UsersAPI:
"""The class provides the user API on the Nextcloud server.
Expand Down
3 changes: 3 additions & 0 deletions nc_py_api/users_groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ def can_remove(self) -> bool:
"""Flag indicating the caller has enough rights to remove users from this group."""
return bool(self._raw_data["canRemove"])

def __repr__(self):
return f"<{self.__class__.__name__} id={self.group_id}, user_count={self.user_count}, disabled={self.disabled}>"


class _UsersGroupsAPI:
"""Class providing an API for managing user groups on the Nextcloud server.
Expand Down
1 change: 1 addition & 0 deletions tests/_talk_bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ def coverage_talk_bot_process_request(message: talk_bot.TalkBotMessage, request:
request._url = URL("sample_url")
talk_bot_app(request)
assert e.value.status_code == 500
assert str(message).find("conversation=") != -1


@APP.post("/talk_bot_coverage")
Expand Down
4 changes: 3 additions & 1 deletion tests/actual_tests/activity_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ def test_get_filters(nc_any):
assert isinstance(i.icon, str)
assert i.name
assert isinstance(i.priority, int)
assert str(i).find("name=") != -1


def test_get_activities(nc_any):
Expand All @@ -37,7 +38,8 @@ def test_get_activities(nc_any):
assert isinstance(i.objects, dict)
assert isinstance(i.link, str)
assert isinstance(i.icon, str)
assert i.activity_time > datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
assert i.time > datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc)
assert str(i).find("app=") != -1
r2 = nc_any.activity.get_activities(since=True)
if r2:
old_activities_id = [i.activity_id for i in r]
Expand Down
1 change: 1 addition & 0 deletions tests/actual_tests/apps_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,4 @@ def test_ex_app_get_list(nc, nc_app):
assert isinstance(app.system, bool)
if app.app_id == "nc_py_api":
assert app.system is True
assert str(app).find("id=") != -1 and str(app).find("ver=") != -1
2 changes: 2 additions & 0 deletions tests/actual_tests/files_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,8 @@ def test_create_update_delete_tag(nc_any):
assert tag.display_name == "test_nc_py_api2"
assert tag.user_visible is False
assert tag.user_assignable is False
for i in nc_any.files.list_tags():
assert str(i).find("name=") != -1
nc_any.files.delete_tag(tag)
with pytest.raises(ValueError):
nc_any.files.update_tag(tag)
Expand Down
1 change: 1 addition & 0 deletions tests/actual_tests/notes_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ def test_create_delete(nc_client):
assert new_note.readonly is False
assert new_note.favorite is False
assert isinstance(new_note.last_modified, datetime)
assert str(new_note).find("title=") != -1


def test_get_update_note(nc_client):
Expand Down
Loading