From ce80607deca9b890d0a77f3ae14d6b84cdaded61 Mon Sep 17 00:00:00 2001 From: joeyagreco Date: Fri, 26 Jan 2024 16:30:57 -0600 Subject: [PATCH] formatting --- pythontextnow/api/Client.py | 19 ++- pythontextnow/api/TextNowAPI.py | 171 ++++++++++--------- pythontextnow/decorator/cooldown.py | 4 +- pythontextnow/enum/ContactType.py | 2 +- pythontextnow/enum/MessageDirection.py | 2 +- pythontextnow/enum/ReadStatus.py | 2 +- pythontextnow/model/Avatar.py | 4 +- pythontextnow/model/Group.py | 14 +- pythontextnow/model/Member.py | 16 +- pythontextnow/model/Message.py | 20 ++- pythontextnow/model/MultiMediaMessage.py | 20 ++- pythontextnow/model/TextMessage.py | 20 ++- pythontextnow/model/User.py | 10 +- pythontextnow/service/ConversationService.py | 70 +++++--- pythontextnow/util/ConfigReader.py | 10 +- pythontextnow/util/CustomFormatter.py | 14 +- pythontextnow/util/CustomLogger.py | 5 +- pythontextnow/util/general.py | 8 +- setup.py | 4 +- test/helper/helper_classes.py | 8 +- test/test_api/test_TextNowAPI.py | 129 +++++++------- 21 files changed, 303 insertions(+), 249 deletions(-) diff --git a/pythontextnow/api/Client.py b/pythontextnow/api/Client.py index 476bf0a..2840a8b 100644 --- a/pythontextnow/api/Client.py +++ b/pythontextnow/api/Client.py @@ -12,6 +12,7 @@ class ClientConfig: """ Used to hold the Client config. """ + username: str headers: dict cookies: dict @@ -22,19 +23,19 @@ class Client: """ This class is used to store and set up initial Client configuration. """ + client_config: Optional[ClientConfig] = None @classmethod def set_client_config(cls, *, username: str, sid_cookie: str) -> None: - headers = { - "user-agent": get_random_user_agent(), - "Cookie": f"connect.sid={sid_cookie};", - } - - client_config = ClientConfig(username=username, - headers=headers, - cookies=dict(), # for now, no cookies are needed - last_call_time=datetime.datetime.now()) + headers = {"user-agent": get_random_user_agent(), "Cookie": f"connect.sid={sid_cookie};"} + + client_config = ClientConfig( + username=username, + headers=headers, + cookies=dict(), # for now, no cookies are needed + last_call_time=datetime.datetime.now(), + ) cls.client_config = client_config @classmethod diff --git a/pythontextnow/api/TextNowAPI.py b/pythontextnow/api/TextNowAPI.py index 60c79e0..da0f1cb 100644 --- a/pythontextnow/api/TextNowAPI.py +++ b/pythontextnow/api/TextNowAPI.py @@ -9,7 +9,7 @@ from pythontextnow.api.Client import Client, ClientConfig from pythontextnow.decorator.cooldown import enforce_cooldown -from pythontextnow.enum import MessageType, MessageDirection, ContactType, ReadStatus +from pythontextnow.enum import ContactType, MessageDirection, MessageType, ReadStatus from pythontextnow.model.Group import Group from pythontextnow.model.Message import Message from pythontextnow.model.MultiMediaMessage import MultiMediaMessage @@ -39,16 +39,18 @@ def __client_config(self) -> ClientConfig: @enforce_cooldown def send_message(self, *, message: str, send_to: str) -> None: - json_data = {"contact_value": send_to, - "contact_type": ContactType.DEFAULT.value, - "message": message, - "read": ReadStatus.READ.value, - "message_direction": MessageDirection.OUTGOING.value, - "message_type": MessageType.TEXT.value, - "from_name": self.__client_config.username, - "has_video": False, - "new": True, - "date": datetime.now().isoformat()} + json_data = { + "contact_value": send_to, + "contact_type": ContactType.DEFAULT.value, + "message": message, + "read": ReadStatus.READ.value, + "message_direction": MessageDirection.OUTGOING.value, + "message_type": MessageType.TEXT.value, + "from_name": self.__client_config.username, + "has_video": False, + "new": True, + "date": datetime.now().isoformat(), + } data = {"json": json.dumps(json_data)} @@ -56,29 +58,40 @@ def send_message(self, *, message: str, send_to: str) -> None: f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__MESSAGES_ROUTE}", headers=self.__client_config.headers, cookies=self.__client_config.cookies, - data=data) + data=data, + ) response.raise_for_status() @enforce_cooldown - def get_messages(self, conversation_phone_number: str, - *, - start_message_id: Optional[str] = None, - page_size: Optional[int], - get_archived: Optional[bool]) -> list[Message]: + def get_messages( + self, + conversation_phone_number: str, + *, + start_message_id: Optional[str] = None, + page_size: Optional[int], + get_archived: Optional[bool], + ) -> list[Message]: """ This gets messages from the conversation with the given phone number. This will get all messages before (but not including) the message with the given start_message_id. If the given page_size is greater than the max allowed (30), will default to 30. """ - page_size = page_size if page_size <= self.__MAX_MESSAGE_RESPONSE_SIZE else self.__MAX_MESSAGE_RESPONSE_SIZE - contact_value = f"+{conversation_phone_number}" if not conversation_phone_number.startswith( - "+") else conversation_phone_number + page_size = ( + page_size + if page_size <= self.__MAX_MESSAGE_RESPONSE_SIZE + else self.__MAX_MESSAGE_RESPONSE_SIZE + ) + contact_value = ( + f"+{conversation_phone_number}" + if not conversation_phone_number.startswith("+") + else conversation_phone_number + ) params = { "contact_value": contact_value, "direction": "past", "page_size": page_size, - "get_archived": 1 if get_archived else 0 + "get_archived": 1 if get_archived else 0, } if start_message_id is not None: params["start_message_id"] = start_message_id @@ -88,7 +101,8 @@ def get_messages(self, conversation_phone_number: str, response = requests.get( url_with_params, headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + cookies=self.__client_config.cookies, + ) response.raise_for_status() message_dicts = response.json()["messages"] @@ -105,22 +119,20 @@ def get_messages(self, conversation_phone_number: str, @enforce_cooldown def mark_message_as_read(self, message: Message) -> None: - clean_number = quote(message.number) url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__CONVERSATIONS_ROUTE}/{clean_number}" - params = { - "latest_message_id": message.id_, - "http_method": "PATCH" - } + params = {"latest_message_id": message.id_, "http_method": "PATCH"} data = {"read": True} - response = requests.patch(url, - params=params, - data=data, - cookies=self.__client_config.cookies, - headers=self.__client_config.headers) + response = requests.patch( + url, + params=params, + data=data, + cookies=self.__client_config.cookies, + headers=self.__client_config.headers, + ) response.raise_for_status() @enforce_cooldown @@ -130,9 +142,9 @@ def delete_message(self, *, message_id: str) -> None: """ url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__MESSAGES_ROUTE}/{message_id}" - response = requests.delete(url, - cookies=self.__client_config.cookies, - headers=self.__client_config.headers) + response = requests.delete( + url, cookies=self.__client_config.cookies, headers=self.__client_config.headers + ) response.raise_for_status() @enforce_cooldown @@ -147,7 +159,8 @@ def get_attachment_url(self, *, message_type: MessageType) -> str: response = requests.get( url_with_params, headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + cookies=self.__client_config.cookies, + ) response.raise_for_status() return response.json()["result"] @@ -158,28 +171,29 @@ def upload_raw_media(self, *, attachment_url: str, raw_media: bytes, media_type: Uploads the given raw_media to the given URL. """ headers = { - 'accept': '*/*', - 'content-type': media_type, - 'accept-language': 'en-US,en;q=0.9', + "accept": "*/*", + "content-type": media_type, + "accept-language": "en-US,en;q=0.9", "mode": "cors", "method": "PUT", - "credentials": 'omit' + "credentials": "omit", } - response = requests.put(attachment_url, - data=raw_media, - headers=headers, - cookies=self.__client_config.cookies) + response = requests.put( + attachment_url, data=raw_media, headers=headers, cookies=self.__client_config.cookies + ) response.raise_for_status() @enforce_cooldown - def send_attachment(self, *, - conversation_phone_number: str, - message_type: MessageType, - file_type: str, - is_video: bool, - attachment_url: str) -> None: - + def send_attachment( + self, + *, + conversation_phone_number: str, + message_type: MessageType, + file_type: str, + is_video: bool, + attachment_url: str, + ) -> None: data = { "contact_value": conversation_phone_number, "contact_type": ContactType.ALTERNATE.value, @@ -191,23 +205,25 @@ def send_attachment(self, *, "new": True, "date": datetime.now().isoformat(), "attachment_url": attachment_url, - "media_type": file_type + "media_type": file_type, } url = f"{self.__BASE_URL}{self.__API_ROUTE}/{self.__VERSION}{self.__SEND_ATTACHMENT_ROUTE}" - response = requests.post(url, - data=data, - headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + response = requests.post( + url, + data=data, + headers=self.__client_config.headers, + cookies=self.__client_config.cookies, + ) response.raise_for_status() @enforce_cooldown def get_groups(self) -> list[Group]: url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__GROUPS_ROUTE}" - response = requests.get(url, - headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + response = requests.get( + url, headers=self.__client_config.headers, cookies=self.__client_config.cookies + ) response.raise_for_status() group_list = list() @@ -218,9 +234,9 @@ def get_groups(self) -> list[Group]: @enforce_cooldown def get_user(self) -> User: url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}" - response = requests.get(url, - headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + response = requests.get( + url, headers=self.__client_config.headers, cookies=self.__client_config.cookies + ) response.raise_for_status() return User.from_dict(response.json()) @@ -232,17 +248,10 @@ def create_group(self, *, phone_numbers: list[str]) -> Group: """ url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__GROUPS_ROUTE}" - data = { - "json": { - "members": list() - } - } + data = {"json": {"members": list()}} for phone_number in phone_numbers: - member = { - "contact_value": phone_number, - "contact_type": ContactType.ALTERNATE.value - } + member = {"contact_value": phone_number, "contact_type": ContactType.ALTERNATE.value} data["json"]["members"].append(member) data = parse.urlencode(data, quote_via=urllib.parse.quote) @@ -252,10 +261,9 @@ def create_group(self, *, phone_numbers: list[str]) -> Group: headers = self.__client_config.headers headers["Content-Type"] = "application/x-www-form-urlencoded; charset=UTF-8" - response = requests.post(url, - data=data, - headers=headers, - cookies=self.__client_config.cookies) + response = requests.post( + url, data=data, headers=headers, cookies=self.__client_config.cookies + ) response.raise_for_status() return Group.from_dict(response.json()) @@ -265,11 +273,14 @@ def delete_conversation(self, *, conversation_phone_number: str) -> None: """ Deletes the conversation with the given phone number. """ - conversation_phone_number = conversation_phone_number if not conversation_phone_number.startswith( - "+") else conversation_phone_number[1:] + conversation_phone_number = ( + conversation_phone_number + if not conversation_phone_number.startswith("+") + else conversation_phone_number[1:] + ) url = f"{self.__BASE_URL}{self.__API_ROUTE}{self.__USERS_ROUTE}/{self.__client_config.username}{self.__CONVERSATIONS_ROUTE}/%2B{conversation_phone_number}" - response = requests.delete(url, - headers=self.__client_config.headers, - cookies=self.__client_config.cookies) + response = requests.delete( + url, headers=self.__client_config.headers, cookies=self.__client_config.cookies + ) response.raise_for_status() diff --git a/pythontextnow/decorator/cooldown.py b/pythontextnow/decorator/cooldown.py index 13915cd..4e8e8b5 100644 --- a/pythontextnow/decorator/cooldown.py +++ b/pythontextnow/decorator/cooldown.py @@ -23,7 +23,9 @@ def wrapFunction(*args, **kwargs): difference_seconds = (now - client_config.last_call_time).total_seconds() if difference_seconds < cooldown_seconds: # enforce cooldown - CustomLogger.getLogger().warning(f"ENFORCING COOLDOWN FOR {cooldown_seconds} SECONDS...") + CustomLogger.getLogger().warning( + f"ENFORCING COOLDOWN FOR {cooldown_seconds} SECONDS..." + ) time.sleep(cooldown_seconds) Client.update(last_call_time=now) return function(*args, **kwargs) diff --git a/pythontextnow/enum/ContactType.py b/pythontextnow/enum/ContactType.py index a47cf60..8f420d3 100644 --- a/pythontextnow/enum/ContactType.py +++ b/pythontextnow/enum/ContactType.py @@ -1,6 +1,6 @@ from __future__ import annotations -from enum import unique, Enum +from enum import Enum, unique @unique diff --git a/pythontextnow/enum/MessageDirection.py b/pythontextnow/enum/MessageDirection.py index 00e03bc..21d337e 100644 --- a/pythontextnow/enum/MessageDirection.py +++ b/pythontextnow/enum/MessageDirection.py @@ -1,6 +1,6 @@ from __future__ import annotations -from enum import unique, Enum +from enum import Enum, unique @unique diff --git a/pythontextnow/enum/ReadStatus.py b/pythontextnow/enum/ReadStatus.py index a64abaa..63f8dc9 100644 --- a/pythontextnow/enum/ReadStatus.py +++ b/pythontextnow/enum/ReadStatus.py @@ -1,4 +1,4 @@ -from enum import unique, Enum +from enum import Enum, unique @unique diff --git a/pythontextnow/model/Avatar.py b/pythontextnow/model/Avatar.py index 8294e63..9bbf5ae 100644 --- a/pythontextnow/model/Avatar.py +++ b/pythontextnow/model/Avatar.py @@ -15,7 +15,7 @@ def from_dict(cls, avatar_dict: dict) -> Avatar: return Avatar( background_color=avatar_dict["background_colour"], picture=avatar_dict["picture"], - initials=avatar_dict["initials"] + initials=avatar_dict["initials"], ) @classmethod @@ -23,5 +23,5 @@ def to_dict(cls, avatar: Avatar) -> dict: return { "background_colour": avatar.background_color, "picture": avatar.picture, - "initials": avatar.initials + "initials": avatar.initials, } diff --git a/pythontextnow/model/Group.py b/pythontextnow/model/Group.py index b47e5de..6b54a9a 100644 --- a/pythontextnow/model/Group.py +++ b/pythontextnow/model/Group.py @@ -21,11 +21,13 @@ def from_dict(cls, group_dict: dict) -> Group: for member_dict in group_dict["members"]: members.append(Member.from_dict(member_dict)) avatar = Avatar.from_dict(group_dict["avatar"]) - return Group(title=group_dict["title"], - avatar=avatar, - members=members, - contact_value=group_dict["contact_value"], - e164_contact_value=group_dict["e164_contact_value"]) + return Group( + title=group_dict["title"], + avatar=avatar, + members=members, + contact_value=group_dict["contact_value"], + e164_contact_value=group_dict["e164_contact_value"], + ) @classmethod def to_dict(cls, group: Group) -> dict: @@ -33,5 +35,5 @@ def to_dict(cls, group: Group) -> dict: "title": group.title, "avatar": Avatar.to_dict(group.avatar), "members": [Member.to_dict(member) for member in group.members], - "contact_value": group.contact_value + "contact_value": group.contact_value, } diff --git a/pythontextnow/model/Member.py b/pythontextnow/model/Member.py index 9a83527..e8c8252 100644 --- a/pythontextnow/model/Member.py +++ b/pythontextnow/model/Member.py @@ -18,12 +18,14 @@ class Member: @classmethod def from_dict(cls, member_dict: dict) -> Member: avatar = Avatar.from_dict(member_dict["avatar"]) - return Member(contact_value=member_dict["contact_value"], - e164_contact_value=member_dict["e164_contact_value"], - contact_type=ContactType.from_value(member_dict["contact_type"]), - display_value=member_dict["display_value"], - contact_name=member_dict["contact_name"], - avatar=avatar) + return Member( + contact_value=member_dict["contact_value"], + e164_contact_value=member_dict["e164_contact_value"], + contact_type=ContactType.from_value(member_dict["contact_type"]), + display_value=member_dict["display_value"], + contact_name=member_dict["contact_name"], + avatar=avatar, + ) @classmethod def to_dict(cls, member: Member) -> dict: @@ -33,5 +35,5 @@ def to_dict(cls, member: Member) -> dict: "contact_value": member.contact_value, "contact_name": member.contact_name, "display_value": member.display_value, - "avatar": avatar_dict + "avatar": avatar_dict, } diff --git a/pythontextnow/model/Message.py b/pythontextnow/model/Message.py index 063dae3..b8c96f5 100644 --- a/pythontextnow/model/Message.py +++ b/pythontextnow/model/Message.py @@ -3,7 +3,7 @@ from dataclasses import dataclass from datetime import datetime -from pythontextnow.enum import MessageType, MessageDirection +from pythontextnow.enum import MessageDirection, MessageType @dataclass(kw_only=True) @@ -27,11 +27,13 @@ def from_dict(cls, message_dict: dict) -> Message: id_ = message_dict["id"] direction = MessageDirection.from_value(message_dict["message_direction"]) raw = message_dict - return Message(number=number, - datetime_=date, - first_contact=first_contact, - message_type=type_, - read=read, - id_=id_, - message_direction=direction, - raw=raw) + return Message( + number=number, + datetime_=date, + first_contact=first_contact, + message_type=type_, + read=read, + id_=id_, + message_direction=direction, + raw=raw, + ) diff --git a/pythontextnow/model/MultiMediaMessage.py b/pythontextnow/model/MultiMediaMessage.py index d131fd8..b8680a4 100644 --- a/pythontextnow/model/MultiMediaMessage.py +++ b/pythontextnow/model/MultiMediaMessage.py @@ -12,12 +12,14 @@ class MultiMediaMessage(Message): @classmethod def from_dict(cls, message_dict: dict) -> MultiMediaMessage: message = Message.from_dict(message_dict) - return MultiMediaMessage(number=message.number, - datetime_=message.datetime_, - first_contact=message.first_contact, - message_type=message.message_type, - read=message.read, - id_=message.id_, - message_direction=message.message_direction, - raw=message.raw, - media=message_dict["message"]) + return MultiMediaMessage( + number=message.number, + datetime_=message.datetime_, + first_contact=message.first_contact, + message_type=message.message_type, + read=message.read, + id_=message.id_, + message_direction=message.message_direction, + raw=message.raw, + media=message_dict["message"], + ) diff --git a/pythontextnow/model/TextMessage.py b/pythontextnow/model/TextMessage.py index 2eb42d1..759323b 100644 --- a/pythontextnow/model/TextMessage.py +++ b/pythontextnow/model/TextMessage.py @@ -12,12 +12,14 @@ class TextMessage(Message): @classmethod def from_dict(cls, message_dict: dict) -> TextMessage: message = Message.from_dict(message_dict) - return TextMessage(number=message.number, - datetime_=message.datetime_, - first_contact=message.first_contact, - message_type=message.message_type, - read=message.read, - id_=message.id_, - message_direction=message.message_direction, - raw=message.raw, - text=message_dict["message"]) + return TextMessage( + number=message.number, + datetime_=message.datetime_, + first_contact=message.first_contact, + message_type=message.message_type, + read=message.read, + id_=message.id_, + message_direction=message.message_direction, + raw=message.raw, + text=message_dict["message"], + ) diff --git a/pythontextnow/model/User.py b/pythontextnow/model/User.py index 364617d..e2bb2ef 100644 --- a/pythontextnow/model/User.py +++ b/pythontextnow/model/User.py @@ -12,7 +12,9 @@ class User: @classmethod def from_dict(cls, user_dict: dict) -> User: - return User(user_id=user_dict["user_id"], - username=user_dict["username"], - email=user_dict["email"], - phone_number=user_dict["phone_number"]) + return User( + user_id=user_dict["user_id"], + username=user_dict["username"], + email=user_dict["email"], + phone_number=user_dict["phone_number"], + ) diff --git a/pythontextnow/service/ConversationService.py b/pythontextnow/service/ConversationService.py index 0bd61ef..84ea83d 100644 --- a/pythontextnow/service/ConversationService.py +++ b/pythontextnow/service/ConversationService.py @@ -1,5 +1,5 @@ import mimetypes -from typing import Optional, Generator +from typing import Generator, Optional import phonenumbers @@ -10,7 +10,6 @@ class ConversationService: - def __init__(self, *, conversation_phone_numbers: list[str]): self.__conversation_phone_numbers = conversation_phone_numbers # check that given phone numbers are well-formed @@ -69,17 +68,31 @@ def __get_conversation_number(self) -> str: # correct amount of members, see if all the numbers match for member in group.members: for needed_number in all_needed_group_numbers: - member_number = member.e164_contact_value if member.e164_contact_value is not None else member.contact_value + member_number = ( + member.e164_contact_value + if member.e164_contact_value is not None + else member.contact_value + ) if needed_number in member_number or member_number in needed_number: # in the group we are looking for matching_numbers.append(member_number) if len(matching_numbers) == len(all_needed_group_numbers): - return group.e164_contact_value if group.e164_contact_value is not None else group.contact_value + return ( + group.e164_contact_value + if group.e164_contact_value is not None + else group.contact_value + ) # unable to find a group that matched all conversation phone numbers # create a new group - new_group = self.__text_now_api.create_group(phone_numbers=self.__conversation_phone_numbers) - return new_group.e164_contact_value if new_group.e164_contact_value is not None else new_group.contact_value + new_group = self.__text_now_api.create_group( + phone_numbers=self.__conversation_phone_numbers + ) + return ( + new_group.e164_contact_value + if new_group.e164_contact_value is not None + else new_group.contact_value + ) def send_message(self, *, message: str): """ @@ -88,10 +101,9 @@ def send_message(self, *, message: str): message = general.replace_newlines(message) self.__text_now_api.send_message(message=message, send_to=self.__conversation_number) - def get_messages(self, - *, - num_messages: Optional[int] = None, - include_archived: bool = True) -> Generator[list[Message], None, None]: + def get_messages( + self, *, num_messages: Optional[int] = None, include_archived: bool = True + ) -> Generator[list[Message], None, None]: """ This yields the last n messages in the conversation with this instance's conversation_phone_number. Where: n = 30 or response_size if given. @@ -108,10 +120,12 @@ def get_messages(self, page_size = num_messages if num_messages is not None else self.__DEFAULT_PAGE_SIZE while num_messages is None or messages_yielded < num_messages and page_size > 0: - messages = self.__text_now_api.get_messages(self.__conversation_number, - start_message_id=start_message_id, - get_archived=include_archived, - page_size=page_size) + messages = self.__text_now_api.get_messages( + self.__conversation_number, + start_message_id=start_message_id, + get_archived=include_archived, + page_size=page_size, + ) if len(messages) > 0: start_message_id = messages[-1].id_ messages_yielded += len(messages) @@ -134,7 +148,9 @@ def mark_as_read(self, *, message: Message = None, messages: list[Message] = Non for message in all_messages: self.__text_now_api.mark_message_as_read(message) - def delete_message(self, *, message: Optional[Message] = None, message_id: Optional[str] = None) -> None: + def delete_message( + self, *, message: Optional[Message] = None, message_id: Optional[str] = None + ) -> None: """ Deletes the given message or message with the given ID. """ @@ -157,7 +173,9 @@ def send_media(self, *, file_path: str): if mime_type is None: raise ValueError("Cannot get media type from media at 'file_path'.") media_type = mime_type[0] # will be something like "video/mp4" or "image/png" - file_type = media_type[0].split("/")[0] # will be something like "video" or "image" or "gif" + file_type = media_type[0].split("/")[ + 0 + ] # will be something like "video" or "image" or "gif" if file_type in self.__BANNED_MEDIA_TYPES: raise ValueError(f"'{file_type} is not an allowed media type.'") is_video = file_type == "video" @@ -168,15 +186,17 @@ def send_media(self, *, file_path: str): attachment_url = self.__text_now_api.get_attachment_url(message_type=message_type) - self.__text_now_api.upload_raw_media(attachment_url=attachment_url, - raw_media=raw_media, - media_type=media_type) - - self.__text_now_api.send_attachment(conversation_phone_number=self.__conversation_number, - message_type=message_type, - file_type=file_type, - is_video=is_video, - attachment_url=attachment_url) + self.__text_now_api.upload_raw_media( + attachment_url=attachment_url, raw_media=raw_media, media_type=media_type + ) + + self.__text_now_api.send_attachment( + conversation_phone_number=self.__conversation_number, + message_type=message_type, + file_type=file_type, + is_video=is_video, + attachment_url=attachment_url, + ) def delete_conversation(self) -> None: """ diff --git a/pythontextnow/util/ConfigReader.py b/pythontextnow/util/ConfigReader.py index 5af5755..1613393 100644 --- a/pythontextnow/util/ConfigReader.py +++ b/pythontextnow/util/ConfigReader.py @@ -6,13 +6,19 @@ class ConfigReader: """ Used to read from .properties files """ + __propertiesFileName = "app.properties" @classmethod def get(cls, section: str, name: str, as_type=None) -> str | list | float: - configParser = configparser.ConfigParser(converters={'list': lambda x: [i.strip() for i in x.split(',')]}) + configParser = configparser.ConfigParser( + converters={"list": lambda x: [i.strip() for i in x.split(",")]} + ) propertiesFilePath = os.path.abspath( - os.path.join(os.path.dirname(os.path.realpath(__file__)), f"../{cls.__propertiesFileName}")) + os.path.join( + os.path.dirname(os.path.realpath(__file__)), f"../{cls.__propertiesFileName}" + ) + ) configParser.read(propertiesFilePath) if as_type == list: return configParser.getlist(section, name) diff --git a/pythontextnow/util/CustomFormatter.py b/pythontextnow/util/CustomFormatter.py index 6f543ac..b6f2c07 100644 --- a/pythontextnow/util/CustomFormatter.py +++ b/pythontextnow/util/CustomFormatter.py @@ -6,12 +6,12 @@ class CustomFormatter(logging.Formatter): Logging colored formatter, adapted from https://stackoverflow.com/a/56944256/3638629 """ - grey = '\x1b[38;21m' - blue = '\x1b[38;5;39m' - yellow = '\x1b[38;5;226m' - red = '\x1b[38;5;196m' - bold_red = '\x1b[31;1m' - reset = '\x1b[0m' + grey = "\x1b[38;21m" + blue = "\x1b[38;5;39m" + yellow = "\x1b[38;5;226m" + red = "\x1b[38;5;196m" + bold_red = "\x1b[31;1m" + reset = "\x1b[0m" def __init__(self, formatStr: str, timeFormatStr: str): super().__init__() @@ -22,7 +22,7 @@ def __init__(self, formatStr: str, timeFormatStr: str): logging.INFO: self.blue + self.__formatStr + self.reset, logging.WARNING: self.yellow + self.__formatStr + self.reset, logging.ERROR: self.red + self.__formatStr + self.reset, - logging.CRITICAL: self.bold_red + self.__formatStr + self.reset + logging.CRITICAL: self.bold_red + self.__formatStr + self.reset, } def format(self, record): diff --git a/pythontextnow/util/CustomLogger.py b/pythontextnow/util/CustomLogger.py index 98d4edf..db24be5 100644 --- a/pythontextnow/util/CustomLogger.py +++ b/pythontextnow/util/CustomLogger.py @@ -7,7 +7,6 @@ class CustomLogger: - @staticmethod def getLogger() -> logging.Logger: # set up logging @@ -20,7 +19,9 @@ def getLogger() -> logging.Logger: handler.setLevel(logging.INFO) handler.setStream(sys.stdout) # set up formatter - formatter = CustomFormatter("%(asctime)-8s %(levelname)-8s %(message)s", "%Y-%m-%d %H:%M:%S") + formatter = CustomFormatter( + "%(asctime)-8s %(levelname)-8s %(message)s", "%Y-%m-%d %H:%M:%S" + ) # set in each other handler.setFormatter(formatter) logger.addHandler(handler) diff --git a/pythontextnow/util/general.py b/pythontextnow/util/general.py index 9d19dd8..c45cc87 100644 --- a/pythontextnow/util/general.py +++ b/pythontextnow/util/general.py @@ -1,17 +1,19 @@ import re -from random_user_agent.params import SoftwareName, OperatingSystem +from random_user_agent.params import OperatingSystem, SoftwareName from random_user_agent.user_agent import UserAgent def replace_newlines(text: str): - return re.sub(r'(? str: software_names = [SoftwareName.CHROME.value] operating_systems = [OperatingSystem.WINDOWS.value, OperatingSystem.LINUX.value] - user_agent_rotator = UserAgent(software_names=software_names, operating_systems=operating_systems, limit=100) + user_agent_rotator = UserAgent( + software_names=software_names, operating_systems=operating_systems, limit=100 + ) # Get Random User Agent String. return user_agent_rotator.get_random_user_agent() diff --git a/setup.py b/setup.py index 5cc6cfb..c1b7818 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,5 @@ license="MIT", include_package_data=True, packages=setuptools.find_packages(exclude=("test", "docs")), - install_requires=["requests", - "setuptools", - "phonenumbers"] + install_requires=["requests", "setuptools", "phonenumbers"], ) diff --git a/test/helper/helper_classes.py b/test/helper/helper_classes.py index 448eaf0..e77eaf0 100644 --- a/test/helper/helper_classes.py +++ b/test/helper/helper_classes.py @@ -18,14 +18,10 @@ def raise_for_status(self): """ http_error_msg = "" if 400 <= self.status_code < 500: - http_error_msg = ( - f"{self.status_code} Client Error" - ) + http_error_msg = f"{self.status_code} Client Error" elif 500 <= self.status_code < 600: - http_error_msg = ( - f"{self.status_code} Server Error" - ) + http_error_msg = f"{self.status_code} Server Error" if http_error_msg: raise HTTPError(http_error_msg, response=self) diff --git a/test/test_api/test_TextNowAPI.py b/test/test_api/test_TextNowAPI.py index c89b012..4f93362 100644 --- a/test/test_api/test_TextNowAPI.py +++ b/test/test_api/test_TextNowAPI.py @@ -1,15 +1,15 @@ import datetime import os -from unittest import mock, TestCase +from test.helper.helper_classes import MockResponse +from unittest import TestCase, mock from pythontextnow.api.Client import Client from pythontextnow.api.TextNowAPI import TextNowAPI -from pythontextnow.enum import MessageType, MessageDirection, ContactType +from pythontextnow.enum import ContactType, MessageDirection, MessageType from pythontextnow.model.Group import Group from pythontextnow.model.MultiMediaMessage import MultiMediaMessage from pythontextnow.model.TextMessage import TextMessage from pythontextnow.model.User import User -from test.helper.helper_classes import MockResponse class TestTextNowAPI(TestCase): @@ -25,15 +25,16 @@ def setUpClass(cls, mock_requests_get): mock_response = MockResponse(dict(), 200, text=dummy_messaging_page_str) mock_requests_get.return_value = mock_response - Client.set_client_config(username="dummy_username", - sid_cookie="dummy_sid_cookie") + Client.set_client_config(username="dummy_username", sid_cookie="dummy_sid_cookie") @mock.patch("requests.post") def test_send_message_happy_path(self, mock_requests_post): mock_response = MockResponse(dict(), 200) mock_requests_post.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.send_message.__wrapped__(text_now_api, message="hello world", send_to="5555555555") + response = text_now_api.send_message.__wrapped__( + text_now_api, message="hello world", send_to="5555555555" + ) self.assertIsNone(response) @@ -48,21 +49,15 @@ def test_get_messages_text_message_happy_path(self, mock_requests_get): "message": "hello world", "read": True, "date": "2000-01-01T01:01:00Z", - "conversation_filtering": { - "first_time_contact": True - } - } - mock_response_dict = { - "status": {}, - "messages": [ - mock_message_dict - ] + "conversation_filtering": {"first_time_contact": True}, } + mock_response_dict = {"status": {}, "messages": [mock_message_dict]} mock_response = MockResponse(mock_response_dict, 200) mock_requests_get.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.get_messages.__wrapped__(text_now_api, conversation_phone_number="1111111111", - page_size=10, get_archived=True) + response = text_now_api.get_messages.__wrapped__( + text_now_api, conversation_phone_number="1111111111", page_size=10, get_archived=True + ) message = response[0] self.assertIsInstance(response, list) @@ -70,7 +65,9 @@ def test_get_messages_text_message_happy_path(self, mock_requests_get): self.assertIsInstance(message, TextMessage) self.assertEqual("id", message.id_) self.assertEqual("contact_value", message.number) - self.assertEqual(datetime.datetime(2000, 1, 1, 1, 1, tzinfo=datetime.timezone.utc), message.datetime_) + self.assertEqual( + datetime.datetime(2000, 1, 1, 1, 1, tzinfo=datetime.timezone.utc), message.datetime_ + ) self.assertTrue(message.first_contact) self.assertEqual(MessageType.TEXT, message.message_type) self.assertTrue(message.read) @@ -89,21 +86,15 @@ def test_get_messages_multi_media_message_happy_path(self, mock_requests_get): "message": "https://test", "read": True, "date": "2000-01-01T01:01:00Z", - "conversation_filtering": { - "first_time_contact": True - } - } - mock_response_dict = { - "status": {}, - "messages": [ - mock_message_dict - ] + "conversation_filtering": {"first_time_contact": True}, } + mock_response_dict = {"status": {}, "messages": [mock_message_dict]} mock_response = MockResponse(mock_response_dict, 200) mock_requests_get.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.get_messages.__wrapped__(text_now_api, conversation_phone_number="1111111111", - page_size=10, get_archived=True) + response = text_now_api.get_messages.__wrapped__( + text_now_api, conversation_phone_number="1111111111", page_size=10, get_archived=True + ) message = response[0] self.assertIsInstance(response, list) @@ -111,7 +102,9 @@ def test_get_messages_multi_media_message_happy_path(self, mock_requests_get): self.assertIsInstance(message, MultiMediaMessage) self.assertEqual("id", message.id_) self.assertEqual("contact_value", message.number) - self.assertEqual(datetime.datetime(2000, 1, 1, 1, 1, tzinfo=datetime.timezone.utc), message.datetime_) + self.assertEqual( + datetime.datetime(2000, 1, 1, 1, 1, tzinfo=datetime.timezone.utc), message.datetime_ + ) self.assertTrue(message.first_contact) self.assertEqual(MessageType.IMAGE, message.message_type) self.assertTrue(message.read) @@ -124,16 +117,20 @@ def test_mark_message_as_read_happy_path(self, mock_requests_patch): mock_response = MockResponse(dict(), 200) mock_requests_patch.return_value = mock_response text_now_api = TextNowAPI() - dummy_message = TextMessage(text=None, - number="1111111111", - datetime_=None, - first_contact=None, - message_type=None, - read=None, - id_="12345", - message_direction=None, - raw=None) - response = text_now_api.mark_message_as_read.__wrapped__(text_now_api, message=dummy_message) + dummy_message = TextMessage( + text=None, + number="1111111111", + datetime_=None, + first_contact=None, + message_type=None, + read=None, + id_="12345", + message_direction=None, + raw=None, + ) + response = text_now_api.mark_message_as_read.__wrapped__( + text_now_api, message=dummy_message + ) self.assertIsNone(response) @@ -148,13 +145,13 @@ def test_delete_message_happy_path(self, mock_requests_delete): @mock.patch("requests.get") def test_get_attachment_url_happy_path(self, mock_requests_get): - mock_response_dict = { - "result": "https://test" - } + mock_response_dict = {"result": "https://test"} mock_response = MockResponse(mock_response_dict, 200) mock_requests_get.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.get_attachment_url.__wrapped__(text_now_api, message_type=MessageType.IMAGE) + response = text_now_api.get_attachment_url.__wrapped__( + text_now_api, message_type=MessageType.IMAGE + ) self.assertIsInstance(response, str) self.assertEqual("https://test", response) @@ -164,9 +161,12 @@ def test_upload_raw_media_happy_path(self, mock_requests_put): mock_response = MockResponse(dict(), 200) mock_requests_put.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.upload_raw_media.__wrapped__(text_now_api, attachment_url="https://test", - raw_media=bytes("some_image_bytes", "utf-8"), - media_type="image/png") + response = text_now_api.upload_raw_media.__wrapped__( + text_now_api, + attachment_url="https://test", + raw_media=bytes("some_image_bytes", "utf-8"), + media_type="image/png", + ) self.assertIsNone(response) @@ -175,11 +175,14 @@ def test_send_attachment_happy_path(self, mock_requests_post): mock_response = MockResponse(dict(), 200) mock_requests_post.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.send_attachment.__wrapped__(text_now_api, conversation_phone_number="1111111111", - message_type=MessageType.IMAGE, - file_type="image", - is_video=False, - attachment_url="https://test") + response = text_now_api.send_attachment.__wrapped__( + text_now_api, + conversation_phone_number="1111111111", + message_type=MessageType.IMAGE, + file_type="image", + is_video=False, + attachment_url="https://test", + ) self.assertIsNone(response) @@ -190,7 +193,7 @@ def test_get_groups_happy_path(self, mock_requests_get): "avatar": { "background_colour": "#000000", "picture": "https://test", - "initials": "initials" + "initials": "initials", }, "members": [ { @@ -202,12 +205,12 @@ def test_get_groups_happy_path(self, mock_requests_get): "avatar": { "background_colour": "#111111", "picture": "https://test", - "initials": "initials" - } + "initials": "initials", + }, } ], "contact_value": "1111111111", - "e164_contact_value": "+1111111111" + "e164_contact_value": "+1111111111", } mock_response = MockResponse([dummy_group], 200) mock_requests_get.return_value = mock_response @@ -239,7 +242,7 @@ def test_get_user_happy_path(self, mock_requests_get): "user_id": 123, "username": "user", "email": "123@email.com", - "phone_number": "1111111111" + "phone_number": "1111111111", } mock_response = MockResponse(dummy_user, 200) mock_requests_get.return_value = mock_response @@ -259,7 +262,7 @@ def test_create_group_happy_path(self, mock_requests_post): "avatar": { "background_colour": "#000000", "picture": "https://test", - "initials": "initials" + "initials": "initials", }, "members": [ { @@ -271,12 +274,12 @@ def test_create_group_happy_path(self, mock_requests_post): "avatar": { "background_colour": "#111111", "picture": "https://test", - "initials": "initials" - } + "initials": "initials", + }, } ], "contact_value": "1111111111", - "e164_contact_value": "+1111111111" + "e164_contact_value": "+1111111111", } mock_response = MockResponse(dummy_group, 200) mock_requests_post.return_value = mock_response @@ -306,6 +309,8 @@ def test_delete_conversation_happy_path(self, mock_requests_delete): mock_response = MockResponse(dict(), 200) mock_requests_delete.return_value = mock_response text_now_api = TextNowAPI() - response = text_now_api.delete_conversation.__wrapped__(text_now_api, conversation_phone_number="+1111111111") + response = text_now_api.delete_conversation.__wrapped__( + text_now_api, conversation_phone_number="+1111111111" + ) self.assertIsNone(response)