Skip to content
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

Feature implement get messages paginated and get labels #34

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
52 changes: 46 additions & 6 deletions gmail_wrapper/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
from googleapiclient import discovery
from googleapiclient.errors import HttpError

from gmail_wrapper.entities import Message, AttachmentBody
from gmail_wrapper.entities import Message, AttachmentBody, Label
from gmail_wrapper.exceptions import (
MessageNotFoundError,
AttachmentNotFoundError,
GmailError,
GmailError, LabelNotFoundError,
)


Expand Down Expand Up @@ -62,6 +62,9 @@ def _make_client_account_json(self, account_json, scopes):
def _messages_resource(self):
return self._client.users().messages()

def _labels_resource(self):
return self._client.users().labels()

def _make_credentials(self, account_json: dict, scopes: list) -> Credentials:
credentials = service_account.Credentials.from_service_account_info(
account_json, scopes=scopes
Expand All @@ -82,10 +85,47 @@ def _execute(self, executable):
raise GmailError()
raise e

def get_raw_messages(self, query="", limit=None):
return self._execute(
self._messages_resource().list(userId=self.email, q=query, maxResults=limit)
)
def get_raw_messages(self, query="", limit=None, page_token=None):
arguments = {"userId": self.email, "q": query, "maxResults": limit}

if page_token:
arguments.update({"pageToken": page_token})

return self._execute(self._messages_resource().list(**arguments))

def get_raw_labels(self):
return self._execute(self._labels_resource().list(userId=self.email))

def get_raw_label(self, label_id):
try:
return self._execute(self._labels_resource().get(userId=self.email, id=label_id))
except HttpError as exception:
if exception.resp.status == 404:
raise LabelNotFoundError(label_id)
raise exception

def get_labels(self):
raw_labels = self.get_raw_labels()

if "labels" not in raw_labels:
return []

return [Label(raw_label) for raw_label in raw_labels['labels']]

def get_label(self, label_id):
raw_label = self.get_raw_label(label_id)

return Label(raw_label)

def get_messages_paginated(self, query="", limit=None, page_token=None):
raw_messages = self.get_raw_messages(query, limit, page_token)

if "messages" not in raw_messages:
return [], None

return [
Message(self, raw_message) for raw_message in raw_messages["messages"]
], raw_messages["nextPageToken"]

def get_messages(self, query="", limit=None):
raw_messages = self.get_raw_messages(query, limit)
Expand Down
17 changes: 17 additions & 0 deletions gmail_wrapper/entities.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,3 +176,20 @@ def archive(self):

def __str__(self):
return "Gmail message: {}".format(self.id)


class Label:
def __init__(self, raw_label):
self._raw = raw_label

@property
def id(self):
return self._raw.get("id")

@property
def name(self):
return self._raw.get("name")

@property
def type(self):
return self._raw.get("type")
8 changes: 8 additions & 0 deletions gmail_wrapper/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,14 @@ def __str__(self):
return f"MessageNotFoundError: Gmail returned 404 when attempting to get message {self.message_id}"


class LabelNotFoundError(Exception):
def __init__(self, label_id):
self.label_id = label_id

def __str__(self):
return f"LabelNotFoundError: Gmail returned 404 when attempting to get label {self.label_id}"


class AttachmentNotFoundError(Exception):
def __init__(self, message_id, attachment_id):
self.message_id = message_id
Expand Down
4 changes: 2 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
-r requirements.txt
pytest==7.3.1
requests==2.31.0
pytest~=7.3.1
requests>=2.28.0
pytest-cov==4.1.0
pytest-mock==3.10.0
pytest-runner==6.0.0
Expand Down
6 changes: 3 additions & 3 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

requests==2.31.0
google-api-core==2.10.2
requests~=2.28.0
google-api-core~=2.10.2
google-api-python-client==1.12.11
google-auth==1.35.0
google-auth~=1.35.0
google-auth-httplib2==0.1.0
googleapis-common-protos==1.59.0
44 changes: 44 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,47 @@ def client(mocker):
return_value=make_gmail_client(mocker),
)
return GmailClient(email="[email protected]", secrets_json_string="{}")


@pytest.fixture
def raw_complete_label():
return {
"id": "Label_192818",
"name": "Label created by user",
"messageListVisibility": "show",
"labelListVisibility": "labelShow",
"type": "user",
"messagesTotal": 90,
"messagesUnread": 20,
"threadsTotal": 55,
"threadsUnread": 12,
"color": {
"textColor": "#ffd6a2",
"backgroundColor": "#ffc8af",
},
}


@pytest.fixture
def raw_incomplete_label():
return {
"id": "Label_192818",
"name": "Label created by user",
"messageListVisibility": "show",
"labelListVisibility": "labelShow",
"type": "user",
"color": {
"textColor": "#ffd6a2",
"backgroundColor": "#ffc8af",
},
}


@pytest.fixture
def get_label_payload(raw_complete_label):
return raw_complete_label


@pytest.fixture
def list_label_payload(raw_incomplete_label):
return {"labels": [raw_incomplete_label, raw_incomplete_label]}
Loading