Add initial project structure with Knuddels API integration

Introduced the foundational codebase for a new Python wrapper to interact with the Knuddels.de API. This includes a .gitignore file to exclude virtual environments and compiled Python files, basic project metadata in pyproject.toml, and license information. Core functionality is added in the `api.py` file within a `Knuddels` class, enabling login, session handling, and GraphQL queries for message management. Accompanying `users.py` and `messages.py` modules define relevant data classes. Also set up a test script to verify login and data retrieval flows.
This commit is contained in:
Kumi 2024-01-13 16:46:59 +01:00
commit 3473e6ed6d
Signed by: kumi
GPG key ID: ECBCC9082395383F
10 changed files with 321 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
venv/
*.pyc
__pycache__/

0
LICENSE Normal file
View file

0
README.md Normal file
View file

23
pyproject.toml Normal file
View file

@ -0,0 +1,23 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "pyknuddels"
version = "0.1.0"
authors = [
{ name="Kumi", email="pyknuddels@kumi.email" },
]
description = "Simple Python wrapper to fetch data from Knuddels.de"
readme = "README.md"
license = { file="LICENSE" }
requires-python = ">=3.10"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
"Operating System :: OS Independent",
]
[project.urls]
"Homepage" = "https://kumig.it/kumitterer/pyknuddels"
"Bug Tracker" = "https://kumig.it/kumitterer/pyknuddels/issues"

View file

View file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,86 @@
from .users import User
from typing import List, Optional
class MessageContent:
text: str
def __init__(self, formatted_text: dict) -> None:
self.formatted_text = formatted_text
def get_text(self) -> str:
return self.formatted_text["text"]["text"]
def get_formatted_text(self) -> str:
return self.formatted_text
@classmethod
def from_dict(cls, data: dict):
obj = cls(data["formattedText"])
return obj
def __repr__(self) -> str:
return f"<MessageContent formatted_text={self.formatted_text}>"
class Message:
sender: User
content: dict
def __init__(self, sender: User, content: MessageContent) -> None:
self.sender = sender
self.content = content
def get_sender(self) -> User:
return self.sender
def get_content(self) -> dict:
return self.content
@classmethod
def from_dict(cls, data: dict):
obj = cls(User.from_dict(data["sender"]), MessageContent.from_dict(data["content"]))
return obj
def __repr__(self) -> str:
return f"<Message sender={self.sender} content={self.content}>"
class Conversation:
id: int
visibility: str
messages: List[Message] = []
otherParticipants: List[User] = []
def __init__(
self, id: int, messages: List[Message], other_participants: List[User]
) -> None:
self.id = id
self.messages = messages
self.other_participants = other_participants
def get_messages(self) -> List[Message]:
return self.messages
def get_other_participants(self) -> List[User]:
return self.other_participants
def get_other_participant(self) -> User:
return self.other_participants[0]
def get_message_count(self) -> int:
return len(self.messages)
@classmethod
def from_dict(cls, data: dict):
obj = cls(data["id"], [], [])
obj.visibility = data["visibility"]
for participant in data["otherParticipants"]:
obj.other_participants.append(User.from_dict(participant))
return obj
def __repr__(self) -> str:
return f"<Conversation id={self.id} visibility={self.visibility} other_participants={self.other_participants}>"

View file

@ -0,0 +1,40 @@
from typing import Optional
class User:
id: int
nick: str
isOnline: bool
canSendImages: bool
menteeStatus: str
age: int
albumPhotosUrl: str
canReceiveMessages: bool
city: str
distance: Optional[int]
gender: str
currentOnlineChannelName: str
latestOnlineChannelName: str
lastOnlineTime: int
profilePicture: str
readMe: dict
relationshipStatus: str
sexualOrientation: str
onlineMinutes: int
isAppBot: bool
isLockedByAutomaticComplaint: bool
automaticComplaintCommand: str
isReportable: bool
interest: Optional[str]
latestClient: Optional[str] #?
authenticityClassification: str
@classmethod
def from_dict(cls, data: dict):
obj = cls()
for key, value in data.items():
setattr(obj, key, value)
return obj
def __repr__(self):
return f"<User id={self.id} nick={self.nick}>"

22
test.py Normal file
View file

@ -0,0 +1,22 @@
import logging
import os
logging.basicConfig(
format="[%(asctime)s] [%(levelname)s] %(message)s",
datefmt="%d.%m.%Y %H:%M:%S",
level=logging.INFO
)
from pyknuddels.classes.api import Knuddels
from pyknuddels.classes.messages import Conversation, Message
knuddels = Knuddels(os.environ["KN_USER"], os.environ["KN_PASSWORD"])
knuddels.login()
conversations = knuddels.messenger_overview(1)
for conversation in conversations:
obj = knuddels.get_conversation(conversation["id"])
obj = Conversation.from_dict(conversation)
print(obj)