Skip to content

Commit 3b5c835

Browse files
committed
adding author date and license in docstring
1 parent c0754c1 commit 3b5c835

File tree

15 files changed

+235
-35
lines changed

15 files changed

+235
-35
lines changed

dsg_lib/async_database_functions/__import_sqlalchemy.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ def import_sqlalchemy() -> Tuple:
3636
Raises:
3737
ImportError: If the SQLAlchemy version is less than the minimum required version.
3838
39+
Author: Mike Ryan
40+
Date: 2024/05/16
41+
License: MIT
3942
"""
4043
min_version = '2.0.0' # Minimum required version of SQLAlchemy
4144

dsg_lib/async_database_functions/async_database.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@
4343
# Create a DatabaseOperations instance
4444
db_ops = database_operations.DatabaseOperations(async_db)
4545
```
46+
47+
Author: Mike Ryan
48+
Date: 2024/05/16
49+
License: MIT
4650
"""
4751

4852

dsg_lib/async_database_functions/base_schema.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ class MyModel(base_schema.SchemaBaseSQLite):
2525
# Define your model-specific columns here my_column =
2626
base_schema.Column(base_schema.String(50))
2727
```
28+
29+
Author: Mike Ryan
30+
Date: 2024/05/16
31+
License: MIT
2832
"""
2933
# TODO: change datetime.datetime.now(datetime.timezone.utc) to \
3034
# datetime.datetime.now(datetime.UTC) once only 3.11+ is supported

dsg_lib/async_database_functions/database_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
db_config.get_db_session() as session:
3939
# Perform your database operations here pass
4040
```
41+
42+
Author: Mike Ryan
43+
Date: 2024/05/16
44+
License: MIT
4145
"""
4246
from contextlib import asynccontextmanager
4347
from typing import Dict

dsg_lib/async_database_functions/database_operations.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
Each method is tested to ensure it performs the expected operation and handles errors correctly. The tests use the pytest-asyncio plugin to run the asynchronous methods in an event loop, and the unittest.mock library to mock the database session and simulate errors.
2020
2121
The tests are organized into a single class, TestDatabaseOperations, which contains one test method for each method in the DatabaseOperations class. Each test method follows the Arrange-Act-Assert pattern: it sets up the necessary objects and state (Arrange), calls the method being tested (Act), and checks that the results are as expected (Assert).
22+
23+
Author: Mike Ryan
24+
Date: 2024/05/16
25+
License: MIT
2226
"""
2327

2428
import time

dsg_lib/common_functions/calendar_functions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,10 @@
4545
4646
This module is part of the dsg_lib package and is used for handling and
4747
converting between month numbers and names.
48+
49+
Author: Mike Ryan
50+
Date: 2024/05/16
51+
License: MIT
4852
"""
4953
from loguru import logger
5054

dsg_lib/common_functions/email_validation.py

Lines changed: 144 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,41 @@
11
# -*- coding: utf-8 -*-
2+
"""
3+
This module provides functionality for validating email addresses.
4+
5+
The main function in this module is `validate_email_address`, which takes an email address and a set of optional parameters to control the validation process. It uses the `email_validator` library to perform the validation and returns a dictionary containing the validation result and other information about the email address.
6+
7+
The module also defines a `DNSType` enum for specifying the type of DNS resolver to use during the validation process.
8+
9+
The `validate_email_address` function supports the following optional parameters:
10+
- `check_deliverability`: If True, the function checks whether the email address is deliverable.
11+
- `test_environment`: If True, the function operates in test mode and does not actually send any emails.
12+
- `allow_smtputf8`: If True, the function allows non-ASCII characters in the email address.
13+
- `allow_empty_local`: If True, the function allows email addresses with an empty local part.
14+
- `allow_quoted_local`: If True, the function allows email addresses with a quoted local part.
15+
- `allow_display_name`: If True, the function allows email addresses with a display name.
16+
- `allow_domain_literal`: If True, the function allows email addresses with a domain literal.
17+
- `globally_deliverable`: If True, the function checks whether the email address is globally deliverable.
18+
- `timeout`: The timeout for the DNS resolver, in seconds.
19+
- `dns_type`: The type of DNS resolver to use, either 'dns' or 'timeout'.
20+
21+
Example:
22+
To use the `validate_email` function in this module, you can do the following:
23+
24+
```python
25+
from email_validation import validate_email
26+
27+
email = "test@example.com"
28+
if validate_email(email):
29+
print(f"{email} is valid.")
30+
else:
31+
print(f"{email} is not valid.")
32+
```
33+
See example for more use or bottom of module for more use examples.
34+
35+
Author: Mike Ryan
36+
Date: 2024/05/16
37+
License: MIT
38+
"""
239
from enum import Enum
340
from typing import Dict, List, Union
441
from loguru import logger
@@ -11,6 +48,15 @@
1148

1249

1350
class DNSType(Enum):
51+
"""
52+
Enum representing the type of DNS resolver to use during email validation.
53+
54+
This enum is used in the `validate_email_address` function to specify the type of DNS resolver to use when checking the deliverability of an email address. The `DNS` option uses a standard DNS resolver, while the `TIMEOUT` option uses a DNS resolver with a specified timeout.
55+
56+
Attributes:
57+
DNS (str): Represents a standard DNS resolver.
58+
TIMEOUT (str): Represents a DNS resolver with a specified timeout.
59+
"""
1460
DNS = "dns"
1561
TIMEOUT = "timeout"
1662

@@ -26,24 +72,58 @@ def validate_email_address(
2672
allow_domain_literal: bool = False,
2773
globally_deliverable: bool = None,
2874
timeout: int = 10,
29-
dns_type: str = 'timeout',
75+
dns_type: str = 'dns',
3076
) -> Dict[str, Union[str, bool, Dict[str, Union[str, bool, List[str]]]]]:
77+
"""
78+
Validates an email address and returns a dictionary with the validation result and other information.
79+
80+
This function uses the `email_validator` library to validate the email address. It supports a variety of optional parameters to control the validation process, such as whether to check deliverability, whether to allow non-ASCII characters, and the type of DNS resolver to use.
3181
82+
Args:
83+
email (str): The email address to validate.
84+
check_deliverability (bool, optional): If True, checks whether the email address is deliverable. Defaults to True.
85+
test_environment (bool, optional): If True, operates in test mode and does not actually send any emails. Defaults to False.
86+
allow_smtputf8 (bool, optional): If True, allows non-ASCII characters in the email address. Defaults to False.
87+
allow_empty_local (bool, optional): If True, allows email addresses with an empty local part. Defaults to False.
88+
allow_quoted_local (bool, optional): If True, allows email addresses with a quoted local part. Defaults to False.
89+
allow_display_name (bool, optional): If True, allows email addresses with a display name. Defaults to False.
90+
allow_domain_literal (bool, optional): If True, allows email addresses with a domain literal. Defaults to False.
91+
globally_deliverable (bool, optional): If True, checks whether the email address is globally deliverable. Defaults to None.
92+
timeout (int, optional): The timeout for the DNS resolver, in seconds. Defaults to 10.
93+
dns_type (str, optional): The type of DNS resolver to use, either 'dns' or 'timeout'. Defaults to 'dns'.
94+
95+
Returns:
96+
Dict[str, Union[str, bool, Dict[str, Union[str, bool, List[str]]]]]: A dictionary containing the validation result and other information about the email address.
97+
98+
Raises:
99+
ValueError: If `dns_type` is not 'dns' or 'timeout'.
100+
EmailUndeliverableError: If the email address is not deliverable.
101+
EmailNotValidError: If the email address is not valid according to the `email_validator` library.
102+
Exception: If any other error occurs during the validation process.
103+
"""
104+
# Log the function call with the provided parameters
32105
logger.debug(f"validate_email_address: {email} with params: {locals()}")
106+
107+
# Initialize the valid flag to False
33108
valid: bool = False
34109

35-
dns_type = dns_type.lower()
110+
# Convert the dns_type to a DNSType enum
111+
try:
112+
dns_type = DNSType(dns_type.lower())
113+
except ValueError:
114+
raise ValueError("dns_type must be either 'dns' or 'timeout'. Default is 'dns' if not provided or input is None.")
36115

37-
if dns_type == 'dns':
116+
# Set up the DNS resolver based on the dns_type
117+
if dns_type == DNSType.DNS:
38118
dns_resolver = caching_resolver(timeout=timeout)
39119
dns_param = {"dns_resolver": dns_resolver}
40-
elif dns_type == 'timeout':
41-
if timeout is None:
120+
elif dns_type == DNSType.TIMEOUT:
121+
if timeout is None or timeout <= 0 or isinstance(timeout, int) is False:
42122
timeout = 5
43123
dns_param = {"timeout": timeout}
44124

125+
# Validate the email address
45126
try:
46-
47127
emailinfo = validate_email(
48128
email,
49129
check_deliverability=check_deliverability,
@@ -55,37 +135,63 @@ def validate_email_address(
55135
**dns_param,
56136
)
57137

138+
# Normalize the email address
58139
email: str = emailinfo.normalized
59140

141+
# Initialize the return dictionary
60142
email_dict: Dict[
61143
str, Union[str, bool, Dict[str, Union[str, bool, List[str]]]]
62144
] = {
63145
"email": email,
64-
"valid": False,
146+
"valid": valid,
65147
"email_data": None,
66148
}
67-
email_data: Dict[str, Union[str, bool, List[str]]] = {}
68-
69-
if hasattr(emailinfo, "mx"):
70-
email_data["mx"] = emailinfo.mx
71-
if emailinfo.mx is not None:
72-
email_dict["valid"] = True
73-
logger.info(f"Email is valid: {email}")
74-
else:
75-
if emailinfo.normalized is not None:
76-
email_dict["valid"] = True
77-
logger.info(F"Email no MX record found: {email}")
78149

150+
# Check the deliverability of the email address
151+
if check_deliverability is False:
152+
email_dict["valid"] = True
153+
logger.info(f"Email is valid: {email}")
154+
elif emailinfo.mx is not None:
155+
email_dict["valid"] = True
156+
logger.info(f"Email is valid: {email}")
157+
else:# pragma: no cover
158+
email_dict["valid"] = False
159+
logger.info(f"Email invalid: {email}")
160+
161+
# Add the email info and parameters to the return dictionary
79162
email_dict["email_data"] = dict(sorted(vars(emailinfo).items()))
163+
email_dict["parameters"]=dict(sorted(locals().items()))
80164

165+
# Print and return the dictionary
166+
print(email_dict)
81167
return email_dict
82168

169+
# Handle EmailUndeliverableError
83170
except EmailUndeliverableError as e:
84-
return {"valid": valid, "email": email, "error": str(e)}
171+
error = str(e)
172+
parameters=dict(sorted(locals().items()))
173+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "EmailUndeliverableError","parameters":parameters}
174+
logger.error(f"EmailUndeliverableError: {email} - {str(e)}")
175+
logger.debug(f"EmailUndeliverableError: {email} - {str(e)}, - {parameters}")
176+
return email_dict
177+
178+
# Handle EmailNotValidError
85179
except EmailNotValidError as e:
86-
return {"valid": valid, "email": email, "error": str(e)}
87-
except Exception as e:
88-
return {"valid": valid, "email": email, "error": str(e)}
180+
error = str(e)
181+
parameters=dict(sorted(locals().items()))
182+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "EmailNotValidError","parameters":parameters}
183+
logger.error(f"EmailNotValidError: {email} - {str(e)}")
184+
logger.debug(f"EmailNotValidError: {email} - {str(e)}, - {parameters}")
185+
return email_dict
186+
187+
# Handle other exceptions
188+
except Exception as e: # pragma: no cover
189+
error = str(e)
190+
parameters=dict(sorted(locals().items()))
191+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "Exception","parameters":parameters}
192+
logger.error(f"Exception: {email} - {str(e)}")
193+
logger.debug(f"Exception: {email} - {str(e)}, - {parameters}")
194+
return email_dict
89195

90196

91197
if __name__ == "__main__":
@@ -116,7 +222,7 @@ def validate_email_address(
116222
'this is"not\\allowed@example.com', # spaces, quotes, and backslashes may only exist when within quoted strings and preceded by a backslash
117223
'this\\ still\\"not\\\\allowed@example.com', # even if escaped (preceded by a backslash), spaces, quotes, and backslashes must still be contained by quotes
118224
"1234567890123456789012345678901234567890123456789012345678901234+x@example.com", # local part is longer than 64 characters
119-
"mike@google.com",
225+
120226
# Emails with empty local part
121227
"@example.com", # only valid if allow_empty_local is True
122228

@@ -142,11 +248,14 @@ def validate_email_address(
142248
"john@doe@example.com", # only one @ is allowed
143249
"john.doe@.com", # domain can't start with a dot
144250
"john.doe@example..com", # domain can't have two consecutive dots
251+
"test@google.com",
145252
]
253+
146254
# create a list of configurations
147255
configurations = [
148256
{"check_deliverability": True, "test_environment": False, "allow_smtputf8": False, "allow_empty_local": False, "allow_quoted_local": False, "allow_display_name": False, "allow_domain_literal": False, "globally_deliverable": None, "timeout": 10, "dns_type": 'timeout'},
149257
{"check_deliverability": False, "test_environment": True, "allow_smtputf8": True, "allow_empty_local": True, "allow_quoted_local": True, "allow_display_name": True, "allow_domain_literal": True, "globally_deliverable": None, "timeout": 5, "dns_type": 'dns'},
258+
{"check_deliverability": True},
150259
# add more configurations here
151260
]
152261

@@ -155,18 +264,18 @@ def validate_email_address(
155264

156265
t0 = time.time()
157266
validity=[]
158-
for _ in range(20):
159-
for email in email_addresses:
160-
for config in configurations:
161-
162-
res = validate_email_address(email, **config)
163-
# if res['valid']:
164-
# pprint.pprint(res, indent=4)
165-
# pprint.pprint(res, indent=4)
166-
# print(f"Time taken: {time.time() - t0:.2f}")
167-
# print(f"Email: {email} is valid: {res['valid']}")
168-
# validity.append(f"Email: {email} is valid: {res['valid']}")
169-
validity.append(res)
267+
268+
for email in email_addresses:
269+
for config in configurations:
270+
271+
res = validate_email_address(email, **config)
272+
# if res['valid']:
273+
# pprint.pprint(res, indent=4)
274+
# pprint.pprint(res, indent=4)
275+
# print(f"Time taken: {time.time() - t0:.2f}")
276+
# print(f"Email: {email} is valid: {res['valid']}")
277+
# validity.append(f"Email: {email} is valid: {res['valid']}")
278+
validity.append(res)
170279
t1 = time.time()
171280
validity = sorted(validity, key=lambda x: x['email'])
172281

dsg_lib/common_functions/file_functions.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
3232
# Outputs: 'complete'
3333
```
34+
35+
Author: Mike Ryan
36+
Date: 2024/05/16
37+
License: MIT
3438
"""
3539

3640
# Import required modules

dsg_lib/common_functions/folder_functions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,12 @@
3131
folder at '/path/to/directory/old_folder'
3232
3333
```
34+
35+
Author: Mike Ryan
36+
Date: 2024/05/16
37+
License: MIT
3438
"""
39+
3540
import re
3641
from datetime import datetime
3742
from pathlib import Path

dsg_lib/common_functions/logging_config.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
logger.warning("This is a warning message")
3131
logger.critical("This is a critical message")
3232
```
33+
34+
Author: Mike Ryan
35+
Date: 2024/05/16
36+
License: MIT
3337
"""
3438

3539
import logging

0 commit comments

Comments
 (0)