Skip to content

Commit 92c788a

Browse files
Ihor BilousIhor Bilous
authored andcommitted
Fix issue #29: Fixed names, changed location of methods
1 parent 6d4dce9 commit 92c788a

File tree

8 files changed

+145
-125
lines changed

8 files changed

+145
-125
lines changed

examples/testing/projects.py

Lines changed: 10 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,25 @@
1-
import logging
2-
from typing import Optional
3-
41
from mailtrap import MailtrapApiClient
52
from mailtrap.models.projects import Project
63

7-
logging.basicConfig(
8-
level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s"
9-
)
10-
114
API_TOKEN = "YOU_API_TOKEN"
125
ACCOUNT_ID = "YOU_ACCOUNT_ID"
136

14-
15-
def find_project_by_name(project_name: str, projects: list[Project]) -> Optional[str]:
16-
filtered_projects = [project for project in projects if project.name == project_name]
17-
if filtered_projects:
18-
return filtered_projects[0].id
19-
return None
20-
21-
22-
logging.info("Starting Mailtrap Testing API example...")
23-
247
client = MailtrapApiClient(token=API_TOKEN)
25-
testing_api = client.get_testing_api(ACCOUNT_ID)
8+
testing_api = client.testing_api(ACCOUNT_ID)
269
projects_api = testing_api.projects
2710

28-
project_name = "Example-project"
29-
created_project = projects_api.create(project_name=project_name)
30-
logging.info(f"Project created! ID: {created_project.id}, Name: {created_project.name}")
3111

32-
projects = projects_api.get_list()
33-
logging.info(f"Found {len(projects)} projects:")
34-
for project in projects:
35-
logging.info(f" - {project.name} (ID: {project.id})")
12+
def list_projects() -> list[Project]:
13+
return projects_api.get_list()
14+
3615

37-
project_id = find_project_by_name(project_name, projects)
38-
if project_id:
39-
logging.info(f"Found project with ID: {project_id}")
40-
else:
41-
logging.info("Project not found in the list")
16+
def create_project(project_name: str) -> Project:
17+
return projects_api.create(project_name=project_name)
4218

43-
if project_id:
44-
project = projects_api.get_by_id(project_id)
45-
logging.info(f"Project details: {project.name} (ID: {project.id})")
4619

47-
new_name = "Updated-project-name"
48-
updated_project = projects_api.update(project_id, new_name)
49-
logging.info(f"Project updated!ID: {project_id}, New name: {updated_project.name}")
20+
def update_project(project_id: str, new_name: str) -> Project:
21+
return projects_api.update(project_id, new_name)
5022

51-
deleted_object = projects_api.delete(project_id)
52-
logging.info(f"Project deleted! Deleted ID: {deleted_object.id}")
5323

54-
logging.info("Example completed successfully!")
24+
def delete_project(project_id: str):
25+
return projects_api.delete(project_id)

mailtrap/api/resources/projects.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from mailtrap.http import HttpClient
2-
from mailtrap.models.base import DeletedObject
2+
from mailtrap.models.common import DeletedObject
33
from mailtrap.models.projects import Project
44

55

@@ -9,7 +9,7 @@ def __init__(self, client: HttpClient, account_id: str) -> None:
99
self.client = client
1010

1111
def get_list(self) -> list[Project]:
12-
response = self.client.list(f"/api/accounts/{self.account_id}/projects")
12+
response = self.client.get(f"/api/accounts/{self.account_id}/projects")
1313
return [Project(**project) for project in response]
1414

1515
def get_by_id(self, project_id: int) -> Project:

mailtrap/client.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,12 @@ class MailtrapApiClient:
107107
def __init__(self, token: str) -> None:
108108
self.token = token
109109

110-
def testing_api(self, account_id: str, inbox_id: str) -> TestingApi:
111-
http_client = HttpClient(host=GENERAL_ENDPOINT, headers=self.get_headers())
110+
def testing_api(self, account_id: str, inbox_id: Optional[str] = None) -> TestingApi:
111+
http_client = HttpClient(host=GENERAL_ENDPOINT, headers=self.headers)
112112
return TestingApi(account_id=account_id, inbox_id=inbox_id, client=http_client)
113113

114-
def get_headers(self) -> dict[str, str]:
114+
@property
115+
def headers(self) -> dict[str, str]:
115116
return {
116117
"Authorization": f"Bearer {self.token}",
117118
"Content-Type": "application/json",

mailtrap/http.py

Lines changed: 40 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -22,40 +22,12 @@ def __init__(
2222
self._session.headers.update(headers or {})
2323
self._timeout = timeout
2424

25-
def _url(self, path: str) -> str:
26-
return f"https://{self._host}/{path.lstrip('/')}"
27-
28-
def _handle_failed_response(self, response: Response) -> NoReturn:
29-
status_code = response.status_code
30-
try:
31-
data = response.json()
32-
except ValueError as exc:
33-
raise APIError(status_code, errors=["Unknown Error"]) from exc
34-
35-
errors = _extract_errors(data)
36-
37-
if status_code == 401:
38-
raise AuthorizationError(errors=errors)
39-
40-
raise APIError(status_code, errors=errors)
41-
42-
def _process_response(self, response: Response) -> Any:
43-
if not response.ok:
44-
self._handle_failed_response(response)
45-
return response.json()
46-
4725
def get(self, path: str, params: Optional[dict[str, Any]] = None) -> Any:
4826
response = self._session.get(
4927
self._url(path), params=params, timeout=self._timeout
5028
)
5129
return self._process_response(response)
5230

53-
def list(self, path: str, params: Optional[dict[str, Any]] = None) -> Any:
54-
response = self._session.get(
55-
self._url(path), params=params, timeout=self._timeout
56-
)
57-
return self._process_response(response)
58-
5931
def post(self, path: str, json: Optional[dict[str, Any]] = None) -> Any:
6032
response = self._session.post(self._url(path), json=json, timeout=self._timeout)
6133
return self._process_response(response)
@@ -72,27 +44,49 @@ def delete(self, path: str) -> Any:
7244
response = self._session.delete(self._url(path), timeout=self._timeout)
7345
return self._process_response(response)
7446

47+
def _url(self, path: str) -> str:
48+
return f"https://{self._host}/{path.lstrip('/')}"
49+
50+
def _process_response(self, response: Response) -> Any:
51+
if not response.ok:
52+
self._handle_failed_response(response)
53+
return response.json()
54+
55+
def _handle_failed_response(self, response: Response) -> NoReturn:
56+
status_code = response.status_code
57+
try:
58+
data = response.json()
59+
except ValueError as exc:
60+
raise APIError(status_code, errors=["Unknown Error"]) from exc
61+
62+
errors = self._extract_errors(data)
63+
64+
if status_code == 401:
65+
raise AuthorizationError(errors=errors)
66+
67+
raise APIError(status_code, errors=errors)
7568

76-
def _extract_errors(data: dict[str, Any]) -> list[str]:
77-
def flatten_errors(errors: Any) -> list[str]:
78-
if isinstance(errors, list):
79-
return [str(error) for error in errors]
69+
@staticmethod
70+
def _extract_errors(data: dict[str, Any]) -> list[str]:
71+
def flatten_errors(errors: Any) -> list[str]:
72+
if isinstance(errors, list):
73+
return [str(error) for error in errors]
8074

81-
if isinstance(errors, dict):
82-
flat_errors = []
83-
for key, value in errors.items():
84-
if isinstance(value, list):
85-
flat_errors.extend([f"{key}: {v}" for v in value])
86-
else:
87-
flat_errors.append(f"{key}: {value}")
88-
return flat_errors
75+
if isinstance(errors, dict):
76+
flat_errors = []
77+
for key, value in errors.items():
78+
if isinstance(value, list):
79+
flat_errors.extend([f"{key}: {v}" for v in value])
80+
else:
81+
flat_errors.append(f"{key}: {value}")
82+
return flat_errors
8983

90-
return [str(errors)]
84+
return [str(errors)]
9185

92-
if "errors" in data:
93-
return flatten_errors(data["errors"])
86+
if "errors" in data:
87+
return flatten_errors(data["errors"])
9488

95-
if "error" in data:
96-
return flatten_errors(data["error"])
89+
if "error" in data:
90+
return flatten_errors(data["error"])
9791

98-
return ["Unknown error"]
92+
return ["Unknown error"]
File renamed without changes.

tests/conftest.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
UNAUTHORIZED_STATUS_CODE = 401
2+
UNAUTHORIZED_ERROR_MESSAGE = "Incorrect API token"
3+
UNAUTHORIZED_RESPONSE = {"error": UNAUTHORIZED_ERROR_MESSAGE}
4+
5+
FORBIDDEN_STATUS_CODE = 403
6+
FORBIDDEN_ERROR_MESSAGE = "Access forbidden"
7+
FORBIDDEN_RESPONSE = {"errors": FORBIDDEN_ERROR_MESSAGE}
8+
9+
NOT_FOUND_STATUS_CODE = 404
10+
NOT_FOUND_ERROR_MESSAGE = "Not Found"
11+
NOT_FOUND_RESPONSE = {"error": NOT_FOUND_ERROR_MESSAGE}

0 commit comments

Comments
 (0)