Skip to content

Commit

Permalink
Add a pre-cookiecutter hook to check for a valid email address format
Browse files Browse the repository at this point in the history
  • Loading branch information
Eric Young committed Apr 27, 2021
1 parent 83c934b commit 95d60b3
Show file tree
Hide file tree
Showing 5 changed files with 85 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/reference/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ in `hooks.*` namespace are public.

```{toctree}
:maxdepth: 2
./pre_gen_project.md
./post_gen_project.md
```
18 changes: 18 additions & 0 deletions docs/reference/pre_gen_project.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Pre-cookiecutter generation hooks

These `hooks` package functions are executed before the project structure has been generated.

<!-- Functions should be referenced in the `hooks.__init__.py` -->
```{eval-rst}
.. currentmodule:: hooks
```

## Cookiecutter input validation

```{eval-rst}
.. autosummary::
:toctree: api/
check_valid_email_address_format
```
1 change: 1 addition & 0 deletions hooks/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
from hooks.post_gen_project import remove_folder, set_aqa_framework, set_request_template
from hooks.pre_gen_project import check_valid_email_address_format
31 changes: 31 additions & 0 deletions hooks/pre_gen_project.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import re

# Regular expression to check for a valid email address — based on the HTML5 standard
# (https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address). This is more restrictive than the RFC
# standard; see the comments in this SO answer for further information: https://stackoverflow.com/a/201378
REGEX_EMAIL_ADDRESS = r"^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?" \
r"(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"


def check_valid_email_address_format(email: str) -> None:
"""Check that an email address is of a valid format using regular expressions.
Uses the HTML5 standard for email address format. The regular expression pattern is available `here`_.
Args:
email: An email address to validate.
Returns:
None - raises an `AssertionError` if `email` is not a valid email address format.
.. _here:
https://html.spec.whatwg.org/multipage/input.html#valid-e-mail-address
"""
assert bool(re.fullmatch(REGEX_EMAIL_ADDRESS, email)), f"Invalid email address supplied: {email}"


if __name__ == "__main__":

# Check the format of the contact email address supplied is a valid one
check_valid_email_address_format("{{ cookiecutter.contact_email }}")
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
from hooks.pre_gen_project import check_valid_email_address_format
import pytest

# Define test cases for the `TestCheckValidEmailAddressFormat` test class
args_invalid_email_addresses = [
"hello.world",
"foo_bar"
]
args_valid_email_addresses = [
"[email protected]",
"foo@bar"
]


class TestCheckValidEmailAddressFormat:

@pytest.mark.parametrize("test_input_email", args_invalid_email_addresses)
def test_raises_assertion_error_for_invalid_emails(self, test_input_email: str) -> None:
"""Test an `AssertionError` is raised for invalid email addresses."""

# Execute the `check_valid_email_address_format` function, and check it raises an `AssertionError`
with pytest.raises(AssertionError):
check_valid_email_address_format(test_input_email)

@pytest.mark.parametrize("test_input_email", args_valid_email_addresses)
def test_passes_for_valid_emails(self, test_input_email: str) -> None:
"""Test no errors are raised for valid email addresses."""

# Execute the `check_valid_email_address_format` function, which should not raise any exceptions for a valid
# email address
try:
check_valid_email_address_format(test_input_email)
except Exception as e:
pytest.fail(f"Error raised: {e}")

0 comments on commit 95d60b3

Please sign in to comment.