Skip to content

Commit

Permalink
Merge 64a53f6 into c872591
Browse files Browse the repository at this point in the history
  • Loading branch information
CarloDePieri committed Aug 19, 2022
2 parents c872591 + 64a53f6 commit 065106a
Show file tree
Hide file tree
Showing 24 changed files with 194 additions and 138 deletions.
229 changes: 126 additions & 103 deletions poetry.lock

Large diffs are not rendered by default.

64 changes: 48 additions & 16 deletions pymailtm/pymailtm.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
from pathlib import Path
from tempfile import NamedTemporaryFile
from time import sleep
from typing import Dict
from typing import Dict, List


class Account:
"""Representing a temprary mailbox."""
"""Representing a temporary mailbox."""

def __init__(self, id, address, password):
self.id_ = id
Expand All @@ -35,14 +35,23 @@ def get_messages(self, page=1):
"""Download a list of messages currently in the account."""
r = requests.get("{}/messages?page={}".format(self.api_address, page),
headers=self.auth_headers)
if r.status_code != 200:
raise CouldNotGetMessagesException(f"Get message list: HTTP {r.status_code}")

messages = []
for message_data in r.json()["hydra:member"]:
# recover full message
sleep(2)
# recover the full message
r = requests.get(
f"{self.api_address}/messages/{message_data['id']}", headers=self.auth_headers)
text = r.json()["text"]
html = r.json()["html"]
# prepare the mssage object
if r.status_code != 200:
raise CouldNotGetMessagesException(f"Get message: HTTP {r.status_code}")

full_message_json = r.json()
text = full_message_json["text"]
html = full_message_json["html"]

# prepare the message object and append it to the list
messages.append(Message(
message_data["id"],
message_data["from"],
Expand All @@ -52,6 +61,7 @@ def get_messages(self, page=1):
text,
html,
message_data))

return messages

def delete_account(self):
Expand All @@ -62,10 +72,25 @@ def delete_account(self):

def wait_for_message(self):
"""Wait for a new message to arrive, then return it."""
start = len(self.get_messages())
while len(self.get_messages()) == start:
sleep(1)
return self.get_messages()[0]
old_messages_id = self._get_existing_messages_id()

while True:
sleep(2)
try:
new_messages = list(filter(lambda m: m.id_ not in old_messages_id, self.get_messages()))
if new_messages:
return new_messages[0]
except CouldNotGetMessagesException:
pass

def _get_existing_messages_id(self) -> List[int]:
"""Return the existing messages id list. This will keep trying, ignoring errors."""
while True:
try:
old_messages = self.get_messages()
return list(map(lambda m: m.id_, old_messages))
except CouldNotGetMessagesException:
sleep(3)

def monitor_account(self):
"""Keep waiting for new messages and open them in the browser."""
Expand Down Expand Up @@ -124,8 +149,12 @@ def open_webbrowser(link: str) -> None:
os.dup2(saverr, 2)


class CouldNotGetMessagesException(Exception):
"""Raised if a GET on /messages returns with a failed status code."""


class CouldNotGetAccountException(Exception):
"""Raised if a POST on /accounts or /authorization_token return a failed status code."""
"""Raised if a POST on /accounts or /authorization_token returns with a failed status code."""


class InvalidDbAccountException(Exception):
Expand All @@ -140,10 +169,13 @@ class MailTm:
db_file = os.path.join(Path.home(), ".pymailtm")

def _get_domains_list(self):
r = requests.get("{}/domains".format(self.api_address))
response = r.json()
domains = list(map(lambda x: x["domain"], response["hydra:member"]))
return domains
while True:
r = requests.get("{}/domains".format(self.api_address))
if r.status_code == 200:
response = r.json()
domains = list(map(lambda x: x["domain"], response["hydra:member"]))
return domains
sleep(2)

def get_account(self, password=None):
"""Create and return a new account."""
Expand Down Expand Up @@ -172,7 +204,7 @@ def _make_account_request(endpoint, address, password):
r = requests.post("{}/{}".format(MailTm.api_address, endpoint),
data=json.dumps(account), headers=headers)
if r.status_code not in [200, 201]:
raise CouldNotGetAccountException()
raise CouldNotGetAccountException(f"HTTP {r.status_code}")
return r.json()

def monitor_new_account(self, force_new=False):
Expand Down
28 changes: 14 additions & 14 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "pymailtm"
version = "1.1.0"
version = "1.1.1"
description = "A python web api wrapper and command line client for mail.tm."

license = "GPL-3.0-only"
Expand Down Expand Up @@ -38,23 +38,23 @@ pymailtm = 'pymailtm.cli:init'

[tool.poetry.dependencies]
python = "^3.7"
requests = "^2.25.1"
requests = "^2.28.1"
random-username = "^1.0.2"
pyperclip = "^1.8.2"

[tool.poetry.dev-dependencies]
anyio = "^2.2.0"
yagmail = "^0.14.245"
pytest = "^6.2.2"
pytest-cov = "^2.11.1"
pytest-mock = "^3.5.1"
pytest-sugar = "^0.9.4"
pytest-spec = "^3.1.0"
pytest-timeout = "^1.4.2"
coveralls = "^3.0.1"
PyYAML = "^5.4.1"
pytest-recording = "^0.12.0"
pytest-vcr-delete-on-fail = "^0.9.0"
anyio = "^3.6.1"
yagmail = "^0.15.283"
pytest = "^7.1.2"
pytest-cov = "^3.0.0"
pytest-mock = "^3.8.2"
pytest-sugar = "^0.9.5"
pytest-spec = "^3.2.0"
pytest-timeout = "^2.1.0"
coveralls = "^3.3.1"
PyYAML = "^6.0"
pytest-recording = "^0.12.1"
pytest-vcr-delete-on-fail = "^2.0.0"
python-dotenv = "^0.20.0"
vcrpy-encrypt = "^0.9.1"

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
11 changes: 6 additions & 5 deletions tests/test_pymailtm.py
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ def test_should_return_an_empty_list_with_no_message(self):
messages = account.get_messages()
assert len(messages) == 0

@pytest.mark.timeout(15)
@pytest.mark.timeout(20)
def test_should_return_messages_if_present(self):
"""... it should return messages, if present"""
account = MailTm().get_account()
Expand All @@ -193,7 +193,7 @@ def test_should_return_messages_if_present(self):
assert message.subject == "subject"
assert message.text == "test"

@pytest.mark.timeout(15)
@pytest.mark.timeout(20)
def test_should_be_able_to_wait_for_and_return_a_new_message(self):
"""... it should be able to wait for and return a new message"""
account = MailTm().get_account()
Expand All @@ -215,7 +215,7 @@ def send_from_another_thread(acc: Account) -> None:
msg = account.wait_for_message()
assert msg.text == "test"

@pytest.mark.timeout(15)
@pytest.mark.timeout(20)
def test_should_be_able_to_monitor_new_messages(self, mocker):
"""... it should be able to monitor new messages"""
account = MailTm().get_account()
Expand Down Expand Up @@ -331,18 +331,19 @@ def crash_on_pyperclip_copy(_):
mt._open_account(new=True)


class TestTheOpenWebbrowserUtility():
class TestTheOpenWebbrowserUtility:
"""The open webbrowser utility..."""

def test_should_call_the_webbrowser_library(self, mocker):
"""... it should call the webbrowser library"""
# noinspection HttpUrlsUsage
url = "http://mail.tm"
mocked_open = mocker.patch("pymailtm.pymailtm.webbrowser.open", new=create_autospec(webbrowser.open))
open_webbrowser(url)
mocked_open.assert_called_once_with(url)


class TestAMailMessage():
class TestAMailMessage:
"""A mail message..."""

def test_has_a_method_to_open_itself_in_a_webbrowser(self, mocker):
Expand Down

0 comments on commit 065106a

Please sign in to comment.