Skip to content

Commit 0bd578d

Browse files
Merge pull request #13 from railsware/deprecate-dead-python-versions
Drop support for Python 3.6-3.8 and add support for 3.12-3.13
2 parents f93adc5 + 8ca3c57 commit 0bd578d

File tree

12 files changed

+58
-85
lines changed

12 files changed

+58
-85
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,15 @@ jobs:
99
strategy:
1010
matrix:
1111
os:
12-
- "ubuntu-20.04"
12+
- "ubuntu-latest"
1313
- "windows-latest"
1414
- "macos-latest"
1515
python:
16-
- "3.6"
17-
- "3.7"
18-
- "3.8"
1916
- "3.9"
2017
- "3.10"
2118
- "3.11"
22-
# Workaround from https://github.com/actions/runner-images/issues/9770
23-
exclude: # Python < v3.8 does not support Apple Silicon ARM64.
24-
- python: "3.6"
25-
os: macos-latest
26-
- python: "3.7"
27-
os: macos-latest
28-
include: # So run those legacy versions on Intel CPUs.
29-
- python: "3.6"
30-
os: macos-13
31-
- python: "3.7"
32-
os: macos-13
19+
- "3.12"
20+
- "3.13"
3321
steps:
3422
- uses: actions/checkout@v4
3523
- name: Setup python

.pre-commit-config.yaml

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
11
repos:
22
- repo: https://github.com/PyCQA/flake8
3-
rev: 5.0.4
3+
rev: 7.2.0
44
hooks:
55
- id: flake8
66
name: Style Guide Enforcement (flake8)
77
args:
88
- '--max-line-length=90'
99
- '--per-file-ignores=__init__.py:F401'
1010
- repo: https://github.com/asottile/pyupgrade
11-
rev: v2.31.0
11+
rev: v3.19.0
1212
hooks:
1313
- id: pyupgrade
1414
name: Upgrade syntax for newer versions of the language (pyupgrade)
1515
args:
16-
- '--py36-plus'
17-
# - repo: https://github.com/pycqa/isort
18-
# rev: 5.10.0
19-
# hooks:
20-
# - id: isort
21-
# name: 'Reorder Python imports'
22-
- repo: https://github.com/PyCQA/docformatter
23-
rev: v1.5.1
16+
- '--py39-plus'
17+
- repo: https://github.com/pycqa/isort
18+
rev: 6.0.1
2419
hooks:
25-
- id: docformatter
26-
name: 'Formats docstrings'
27-
args:
28-
- '--in-place'
20+
- id: isort
21+
name: Reorder Python imports
22+
# - repo: https://github.com/PyCQA/docformatter
23+
# rev: v1.7.5 # incompatible with pre-commit > 4.0.0, but should be fixed in the next release
24+
# hooks:
25+
# - id: docformatter
26+
# name: Formats docstrings
27+
# args:
28+
# - '--in-place '
2929
- repo: 'https://github.com/pre-commit/pre-commit-hooks'
30-
rev: v4.1.0
30+
rev: v5.0.0
3131
hooks:
3232
- id: trailing-whitespace
3333
- id: end-of-file-fixer
3434
- id: check-toml
3535
- repo: https://github.com/python/black
36-
rev: 22.8.0
36+
rev: 25.1.0
3737
hooks:
3838
- id: black
3939
name: Uncompromising Code Formatter (black)

mailtrap/client.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
from typing import Dict
2-
from typing import List
31
from typing import NoReturn
42
from typing import Union
53

@@ -24,12 +22,12 @@ def __init__(
2422
self.api_host = api_host
2523
self.api_port = api_port
2624

27-
def send(self, mail: BaseMail) -> Dict[str, Union[bool, List[str]]]:
25+
def send(self, mail: BaseMail) -> dict[str, Union[bool, list[str]]]:
2826
url = f"{self.base_url}/api/send"
2927
response = requests.post(url, headers=self.headers, json=mail.api_data)
3028

3129
if response.ok:
32-
data = response.json() # type: Dict[str, Union[bool, List[str]]]
30+
data: dict[str, Union[bool, list[str]]] = response.json()
3331
return data
3432

3533
self._handle_failed_response(response)
@@ -39,7 +37,7 @@ def base_url(self) -> str:
3937
return f"https://{self.api_host.rstrip('/')}:{self.api_port}"
4038

4139
@property
42-
def headers(self) -> Dict[str, str]:
40+
def headers(self) -> dict[str, str]:
4341
return {
4442
"Authorization": f"Bearer {self.token}",
4543
"Content-Type": "application/json",

mailtrap/exceptions.py

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,15 @@
1-
from typing import List
2-
3-
41
class MailtrapError(Exception):
52
pass
63

74

85
class APIError(MailtrapError):
9-
def __init__(self, status: int, errors: List[str]) -> None:
6+
def __init__(self, status: int, errors: list[str]) -> None:
107
self.status = status
118
self.errors = errors
129

1310
super().__init__("; ".join(errors))
1411

1512

1613
class AuthorizationError(APIError):
17-
def __init__(self, errors: List[str]) -> None:
14+
def __init__(self, errors: list[str]) -> None:
1815
super().__init__(status=401, errors=errors)

mailtrap/mail/address.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
from typing import Any
2-
from typing import Dict
32
from typing import Optional
43

54
from mailtrap.mail.base_entity import BaseEntity
@@ -11,5 +10,5 @@ def __init__(self, email: str, name: Optional[str] = None) -> None:
1110
self.name = name
1211

1312
@property
14-
def api_data(self) -> Dict[str, Any]:
13+
def api_data(self) -> dict[str, Any]:
1514
return self.omit_none_values({"email": self.email, "name": self.name})

mailtrap/mail/attachment.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
from enum import Enum
22
from typing import Any
3-
from typing import Dict
43
from typing import Optional
54

65
from mailtrap.mail.base_entity import BaseEntity
@@ -27,7 +26,7 @@ def __init__(
2726
self.content_id = content_id
2827

2928
@property
30-
def api_data(self) -> Dict[str, Any]:
29+
def api_data(self) -> dict[str, Any]:
3130
return self.omit_none_values(
3231
{
3332
"content": self.content.decode(),

mailtrap/mail/base.py

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
from abc import ABCMeta
2+
from collections.abc import Sequence
23
from typing import Any
3-
from typing import Dict
4-
from typing import List
54
from typing import Optional
6-
from typing import Sequence
75

86
from mailtrap.mail.address import Address
97
from mailtrap.mail.attachment import Attachment
@@ -16,12 +14,12 @@ class BaseMail(BaseEntity, metaclass=ABCMeta):
1614
def __init__(
1715
self,
1816
sender: Address,
19-
to: List[Address],
20-
cc: Optional[List[Address]] = None,
21-
bcc: Optional[List[Address]] = None,
22-
attachments: Optional[List[Attachment]] = None,
23-
headers: Optional[Dict[str, str]] = None,
24-
custom_variables: Optional[Dict[str, Any]] = None,
17+
to: list[Address],
18+
cc: Optional[list[Address]] = None,
19+
bcc: Optional[list[Address]] = None,
20+
attachments: Optional[list[Attachment]] = None,
21+
headers: Optional[dict[str, str]] = None,
22+
custom_variables: Optional[dict[str, Any]] = None,
2523
) -> None:
2624
self.sender = sender
2725
self.to = to
@@ -32,7 +30,7 @@ def __init__(
3230
self.custom_variables = custom_variables
3331

3432
@property
35-
def api_data(self) -> Dict[str, Any]:
33+
def api_data(self) -> dict[str, Any]:
3634
return self.omit_none_values(
3735
{
3836
"from": self.sender.api_data,
@@ -48,7 +46,7 @@ def api_data(self) -> Dict[str, Any]:
4846
@staticmethod
4947
def get_api_data_from_list(
5048
items: Optional[Sequence[BaseEntity]],
51-
) -> Optional[List[Dict[str, Any]]]:
49+
) -> Optional[list[dict[str, Any]]]:
5250
if items is None:
5351
return None
5452

mailtrap/mail/base_entity.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
from abc import ABCMeta
22
from abc import abstractmethod
33
from typing import Any
4-
from typing import Dict
54

65

76
class BaseEntity(metaclass=ABCMeta):
87
@property
98
@abstractmethod
10-
def api_data(self) -> Dict[str, Any]:
9+
def api_data(self) -> dict[str, Any]:
1110
raise NotImplementedError
1211

1312
@staticmethod
14-
def omit_none_values(data: Dict[str, Any]) -> Dict[str, Any]:
13+
def omit_none_values(data: dict[str, Any]) -> dict[str, Any]:
1514
return {key: value for key, value in data.items() if value is not None}

mailtrap/mail/from_template.py

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from typing import Any
2-
from typing import Dict
3-
from typing import List
42
from typing import Optional
53

64
from mailtrap.mail.address import Address
@@ -15,14 +13,14 @@ class MailFromTemplate(BaseMail):
1513
def __init__(
1614
self,
1715
sender: Address,
18-
to: List[Address],
16+
to: list[Address],
1917
template_uuid: str,
20-
template_variables: Optional[Dict[str, Any]] = None,
21-
cc: Optional[List[Address]] = None,
22-
bcc: Optional[List[Address]] = None,
23-
attachments: Optional[List[Attachment]] = None,
24-
headers: Optional[Dict[str, str]] = None,
25-
custom_variables: Optional[Dict[str, Any]] = None,
18+
template_variables: Optional[dict[str, Any]] = None,
19+
cc: Optional[list[Address]] = None,
20+
bcc: Optional[list[Address]] = None,
21+
attachments: Optional[list[Attachment]] = None,
22+
headers: Optional[dict[str, str]] = None,
23+
custom_variables: Optional[dict[str, Any]] = None,
2624
) -> None:
2725
super().__init__(
2826
sender=sender,
@@ -37,7 +35,7 @@ def __init__(
3735
self.template_variables = template_variables
3836

3937
@property
40-
def api_data(self) -> Dict[str, Any]:
38+
def api_data(self) -> dict[str, Any]:
4139
return self.omit_none_values(
4240
{
4341
**super().api_data,

mailtrap/mail/mail.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from typing import Any
2-
from typing import Dict
3-
from typing import List
42
from typing import Optional
53

64
from mailtrap.mail.address import Address
@@ -23,16 +21,16 @@ class Mail(BaseMail):
2321
def __init__(
2422
self,
2523
sender: Address,
26-
to: List[Address],
24+
to: list[Address],
2725
subject: str,
2826
text: Optional[str] = None,
2927
html: Optional[str] = None,
3028
category: Optional[str] = None,
31-
cc: Optional[List[Address]] = None,
32-
bcc: Optional[List[Address]] = None,
33-
attachments: Optional[List[Attachment]] = None,
34-
headers: Optional[Dict[str, str]] = None,
35-
custom_variables: Optional[Dict[str, Any]] = None,
29+
cc: Optional[list[Address]] = None,
30+
bcc: Optional[list[Address]] = None,
31+
attachments: Optional[list[Attachment]] = None,
32+
headers: Optional[dict[str, str]] = None,
33+
custom_variables: Optional[dict[str, Any]] = None,
3634
) -> None:
3735
super().__init__(
3836
sender=sender,
@@ -49,7 +47,7 @@ def __init__(
4947
self.category = category
5048

5149
@property
52-
def api_data(self) -> Dict[str, Any]:
50+
def api_data(self) -> dict[str, Any]:
5351
return self.omit_none_values(
5452
{
5553
**super().api_data,

0 commit comments

Comments
 (0)