Skip to content

Commit

Permalink
Merge pull request #20 from jpsca/tooling
Browse files Browse the repository at this point in the history
Tests automatically and in more versions
  • Loading branch information
jpsca committed Apr 24, 2023
2 parents 548a802 + 1aff1ea commit 4569067
Show file tree
Hide file tree
Showing 15 changed files with 206 additions and 174 deletions.
41 changes: 41 additions & 0 deletions .github/workflows/run_tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: run_tests
on:
push:
branches:
- main
pull_request:
branches:
- main
jobs:
lint:
name: lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: "Installs dependencies"
run: |
pip install -U pip wheel
pip install -e .[test]
- name: "Run linter"
run: make lint
tests:
name: tests
strategy:
matrix:
python: ["3.7", "3.8", "3.9", "3.10", "3.11"]
fail-fast: false
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: ${{ matrix.python }}
- name: "Installs dependencies"
run: |
pip install -U pip wheel
pip install -e .[test]
- name: "Run tests"
run: make test
32 changes: 32 additions & 0 deletions .github/workflows/upload-to-pypi.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Upload to PyPI

on:
# Triggers the workflow when a release is created
release:
types: [created]
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

jobs:
upload:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/setup-python@v2
with:
python-version: 3.9

- name: "Installs dependencies"
run: |
python3 -m pip install --upgrade pip
python3 -m pip install setuptools wheel build twine
- name: "Builds and uploads to PyPI"
run: |
python3 -m build
python3 -m twine check dist/*
python3 -m twine upload dist/*
env:
TWINE_USERNAME: __token__
TWINE_PASSWORD: ${{ secrets.TWINE_TOKEN }}
11 changes: 0 additions & 11 deletions .travis.yml

This file was deleted.

9 changes: 0 additions & 9 deletions CHANGELOG.md

This file was deleted.

6 changes: 2 additions & 4 deletions mailshake/mailers/amazon_ses.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@ def __init__(
*args,
**kwargs
):
"""
"""
""" """
import boto3

self.client = boto3.client(
Expand All @@ -35,8 +34,7 @@ def __init__(
super(AmazonSESMailer, self).__init__(*args, **kwargs)

def send_messages(self, *email_messages):
"""
"""
""" """
logger = logging.getLogger("mailshake:AmazonSESMailer")
if not email_messages:
logger.debug("No email messages to send")
Expand Down
3 changes: 1 addition & 2 deletions mailshake/mailers/filebased.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ def __init__(self, path, multifile=True, *args, **kwargs):
super(ToFileMailer, self).__init__(*args, **kwargs)

def _get_filename(self):
"""Return a unique file name.
"""
"""Return a unique file name."""
if self._fname is None:
now = datetime.datetime.now()
timestamp = now.strftime("%Y%m%d-%H%M%S")
Expand Down
3 changes: 1 addition & 2 deletions mailshake/mailers/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def __init__(self, *args, **kwargs):
super(ToMemoryMailer, self).__init__(*args, **kwargs)

def send_messages(self, *email_messages):
"""Redirect messages to the dummy outbox.
"""
"""Redirect messages to the dummy outbox."""
self.outbox.extend(email_messages)
return len(email_messages)
6 changes: 2 additions & 4 deletions mailshake/mailers/smtp.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,7 @@ def open(self, hostname=None):
return True

def close(self):
"""Closes the connection to the email server.
"""
"""Closes the connection to the email server."""
if self.connection is None:
return
try:
Expand Down Expand Up @@ -125,8 +124,7 @@ def send_messages(self, *email_messages):
return num_sent

def _send(self, message):
"""A helper method that does the actual sending.
"""
"""A helper method that does the actual sending."""
recipients = message.get_recipients()
if not recipients:
return False
Expand Down
3 changes: 1 addition & 2 deletions mailshake/message.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ def __init__(

class EmailMessage:

"""A container for email information.
"""
"""A container for email information."""

content_subtype = "plain"
mixed_subtype = "mixed"
Expand Down
6 changes: 2 additions & 4 deletions mailshake/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,7 @@ def make_msgid(idstring=None, host_id=DNS_NAME):


def forbid_multi_line_headers(name, val):
"""Forbids multi-line headers, to prevent header injection.
"""
"""Forbids multi-line headers, to prevent header injection."""
if "\n" in val or "\r" in val:
raise ValueError(
"Header values can't contain newlines "
Expand All @@ -124,8 +123,7 @@ def forbid_multi_line_headers(name, val):


def to_str(s, encoding="utf-8", errors="strict"):
"""Force a string to be the native text_type
"""
"""Force a string to be the native text_type"""
if isinstance(s, str):
return s
return str(s, encoding, errors)
46 changes: 31 additions & 15 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[metadata]
name = mailshake
version= 2.2
version = 2.3
url = https://github.com/jpsca/mailshake
project_urls =
Issue tracker = https://github.com/jpsca/mailshake/issues
Expand Down Expand Up @@ -32,32 +32,48 @@ test =
flake8
pytest
pytest-cov
smtpdfix

dev =
black
flake8
pytest
pytest-cov
tox

[flake8]
select =
B, # bugbear
B9, # bugbear opinionated
C, # mccabe, comprehensions, commas
E, # pycodestyle errors
F, # pyflakes
G, # logging format
I, # imports
# bugbear
B,
# bugbear opinionated
B9,
# mccabe, comprehensions, commas
C,
# pycodestyle errors
E,
# pyflakes
F,
# logging format
G,
# imports
I,
P,
Q, # quotes
RST, # rst docstring formatting
T0, # print
T4, # mypy
W, # pycodestyle warnings
# quotes
Q,
# rst docstring formatting
RST,
# print
T0,
# mypy
T4,
# pycodestyle warnings
W,

ignore =
W503, # W503 line break before binary operator
E203, # E203 whitespace before ':'
# W503 line break before binary operator
W503,
# E203 whitespace before ':'
E203,

max-complexity = 10
max-line-length = 88
Expand Down
3 changes: 1 addition & 2 deletions tests/test_mailers.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,7 @@ def test_to_console_mailer():


def test_to_console_stream_kwarg():
"""Test that the console backend can be pointed at an arbitrary stream.
"""
"""Test that the console backend can be pointed at an arbitrary stream."""
s = StringIO()
mailer = ToConsoleMailer(stream=s)
mailer.send("Subject", "Content", "from@example.com", "to@example.com")
Expand Down
27 changes: 16 additions & 11 deletions tests/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,8 +216,7 @@ def test_message_header_overrides():


def test_from_header():
"""Make sure we can manually set the From header.
"""
"""Make sure we can manually set the From header."""
email = EmailMessage(
"Subject",
"Content",
Expand Down Expand Up @@ -436,8 +435,7 @@ def test_dont_mangle_from_in_body():


def test_dont_base64_encode():
"""Shouldn't use Base64 encoding at all.
"""
"""Shouldn't use Base64 encoding at all."""
email = EmailMessage(
"Subject",
"UTF-8 encoded body",
Expand Down Expand Up @@ -505,15 +503,22 @@ def test_invalid_destination():
assert message["To"] != dest


rx_message_id = re.compile(
r"^<[0-9]{14}\.[0-9]+\.[0-9a-f]+\.[0-9]+@[a-z0-9\-]+(\.[a-z0-9\-]+)*>$",
re.IGNORECASE,
)


def test_message_id():
message_id_re = re.compile(
r"^<[0-9]{14}\.[0-9]+\.[0-9a-f]+\.[0-9]+@[a-z\-]+(\.[a-z\-]+)*>$",
re.IGNORECASE
)
email1 = EmailMessage("Subject 1", "Content", "from@example.com", "to@example.com")
msg1 = email1.render()
assert message_id_re.match(msg1["Message-ID"])
mid1 = msg1["Message-ID"]
print("Message-ID 1:", mid1)
assert rx_message_id.match(mid1)

email2 = EmailMessage("Subject 2", "Content", "from@example.com", "to@example.com")
msg2 = email2.render()
assert message_id_re.match(msg2["Message-ID"])
assert msg2["Message-ID"] != msg1["Message-ID"]
mid2 = msg2["Message-ID"]
print("Message-ID 2:", mid2)
assert rx_message_id.match(mid2)
assert mid2 != mid1

0 comments on commit 4569067

Please sign in to comment.