devsetgo-lib 0.12.2__tar.gz → 0.12.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/PKG-INFO +14 -6
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/README.md +12 -5
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/__init__.py +1 -1
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/__import_sqlalchemy.py +3 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/async_database.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/base_schema.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_config.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_operations.py +6 -3
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/calendar_functions.py +4 -0
- devsetgo_lib-0.12.4/dsg_lib/common_functions/email_validation.py +276 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/file_functions.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/folder_functions.py +5 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/logging_config.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/patterns.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/_all_codes.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/http_codes.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/system_health_endpoints.py +4 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/pyproject.toml +9 -5
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/.gitignore +0 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/LICENSE +0 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/__init__.py +0 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/__init__.py +0 -0
- {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/__init__.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: devsetgo_lib
|
|
3
|
-
Version: 0.12.
|
|
3
|
+
Version: 0.12.4
|
|
4
4
|
Summary: DevSetGo Common Library provides reusable Python functions for enhanced code efficiency. It includes utilities for file operations, calendar, pattern matching, logging, FastAPI endpoints, and async database handling with CRUD operations.
|
|
5
5
|
Project-URL: Homepage, https://github.com/devsetgo/devsetgo_lib
|
|
6
6
|
Project-URL: Documentation, https://devsetgo.github.io/devsetgo_lib/
|
|
@@ -41,6 +41,7 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
41
41
|
Classifier: Programming Language :: Python :: 3.11
|
|
42
42
|
Classifier: Programming Language :: Python :: 3.12
|
|
43
43
|
Requires-Python: >=3.9
|
|
44
|
+
Requires-Dist: email-validator>=2.1.1
|
|
44
45
|
Requires-Dist: loguru>=0.7.0
|
|
45
46
|
Requires-Dist: packaging>=20.0
|
|
46
47
|
Provides-Extra: all
|
|
@@ -71,17 +72,21 @@ Description-Content-Type: text/markdown
|
|
|
71
72
|
Python:
|
|
72
73
|
|
|
73
74
|
[](https://pypi.python.org/pypi/devsetgo-lib/)
|
|
74
|
-
|
|
75
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
76
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
77
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
78
|
+
|
|
79
|
+
Support Python Versions
|
|
80
|
+
|
|
81
|
+

|
|
82
|
+
[](https://github.com/astral-sh/ruff)
|
|
75
83
|
|
|
76
|
-
[](https://www.python.org/downloads/release/python-390/)
|
|
77
|
-
[](https://www.python.org/downloads/release/python-3100/)
|
|
78
|
-
[](https://www.python.org/downloads/release/python-3110/)
|
|
79
|
-
[](https://www.python.org/downloads/release/python-3120/)
|
|
80
84
|
|
|
81
85
|
CI/CD Pipeline:
|
|
82
86
|
|
|
83
87
|
[](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
|
|
84
88
|
[](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
|
|
89
|
+
[](https://github.com/devsetgo/dsg_lib)
|
|
85
90
|
|
|
86
91
|
SonarCloud:
|
|
87
92
|
|
|
@@ -92,6 +97,9 @@ SonarCloud:
|
|
|
92
97
|
[](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
|
|
93
98
|
[](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
|
|
94
99
|
|
|
100
|
+

|
|
101
|
+
|
|
102
|
+
|
|
95
103
|
# DevSetGo Common Library
|
|
96
104
|
|
|
97
105
|
## Introduction
|
|
@@ -1,17 +1,21 @@
|
|
|
1
1
|
Python:
|
|
2
2
|
|
|
3
3
|
[](https://pypi.python.org/pypi/devsetgo-lib/)
|
|
4
|
-
|
|
4
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
5
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
6
|
+
[](https://pepy.tech/project/devsetgo-lib)
|
|
7
|
+
|
|
8
|
+
Support Python Versions
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
[](https://github.com/astral-sh/ruff)
|
|
5
12
|
|
|
6
|
-
[](https://www.python.org/downloads/release/python-390/)
|
|
7
|
-
[](https://www.python.org/downloads/release/python-3100/)
|
|
8
|
-
[](https://www.python.org/downloads/release/python-3110/)
|
|
9
|
-
[](https://www.python.org/downloads/release/python-3120/)
|
|
10
13
|
|
|
11
14
|
CI/CD Pipeline:
|
|
12
15
|
|
|
13
16
|
[](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
|
|
14
17
|
[](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
|
|
18
|
+
[](https://github.com/devsetgo/dsg_lib)
|
|
15
19
|
|
|
16
20
|
SonarCloud:
|
|
17
21
|
|
|
@@ -22,6 +26,9 @@ SonarCloud:
|
|
|
22
26
|
[](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
|
|
23
27
|
[](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
|
|
24
28
|
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
|
|
25
32
|
# DevSetGo Common Library
|
|
26
33
|
|
|
27
34
|
## Introduction
|
{devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/__import_sqlalchemy.py
RENAMED
|
@@ -36,6 +36,9 @@ def import_sqlalchemy() -> Tuple:
|
|
|
36
36
|
Raises:
|
|
37
37
|
ImportError: If the SQLAlchemy version is less than the minimum required version.
|
|
38
38
|
|
|
39
|
+
Author: Mike Ryan
|
|
40
|
+
Date: 2024/05/16
|
|
41
|
+
License: MIT
|
|
39
42
|
"""
|
|
40
43
|
min_version = '2.0.0' # Minimum required version of SQLAlchemy
|
|
41
44
|
|
|
@@ -25,6 +25,10 @@ class MyModel(base_schema.SchemaBaseSQLite):
|
|
|
25
25
|
# Define your model-specific columns here my_column =
|
|
26
26
|
base_schema.Column(base_schema.String(50))
|
|
27
27
|
```
|
|
28
|
+
|
|
29
|
+
Author: Mike Ryan
|
|
30
|
+
Date: 2024/05/16
|
|
31
|
+
License: MIT
|
|
28
32
|
"""
|
|
29
33
|
# TODO: change datetime.datetime.now(datetime.timezone.utc) to \
|
|
30
34
|
# datetime.datetime.now(datetime.UTC) once only 3.11+ is supported
|
{devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_config.py
RENAMED
|
@@ -38,6 +38,10 @@ from dsg_lib.async_database_functions import database_config
|
|
|
38
38
|
db_config.get_db_session() as session:
|
|
39
39
|
# Perform your database operations here pass
|
|
40
40
|
```
|
|
41
|
+
|
|
42
|
+
Author: Mike Ryan
|
|
43
|
+
Date: 2024/05/16
|
|
44
|
+
License: MIT
|
|
41
45
|
"""
|
|
42
46
|
from contextlib import asynccontextmanager
|
|
43
47
|
from typing import Dict
|
{devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_operations.py
RENAMED
|
@@ -19,6 +19,10 @@ The methods include:
|
|
|
19
19
|
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.
|
|
20
20
|
|
|
21
21
|
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
|
|
22
26
|
"""
|
|
23
27
|
|
|
24
28
|
import time
|
|
@@ -29,7 +33,6 @@ from sqlalchemy import delete
|
|
|
29
33
|
from sqlalchemy.ext.declarative import DeclarativeMeta
|
|
30
34
|
|
|
31
35
|
from .__import_sqlalchemy import import_sqlalchemy
|
|
32
|
-
|
|
33
36
|
# Importing AsyncDatabase class from local module async_database
|
|
34
37
|
from .async_database import AsyncDatabase
|
|
35
38
|
|
|
@@ -793,7 +796,7 @@ class DatabaseOperations:
|
|
|
793
796
|
records = result.scalars().all()
|
|
794
797
|
logger.debug(f'read_query result: {records}')
|
|
795
798
|
# Log the successful query execution
|
|
796
|
-
if all(isinstance(record, tuple) for record in records):
|
|
799
|
+
if all(isinstance(record, tuple) for record in records): #pragma: no cover
|
|
797
800
|
logger.debug(f'read_query result is a tuple {type(records)}')
|
|
798
801
|
# If all records are tuples, convert them to dictionaries
|
|
799
802
|
records_data = [
|
|
@@ -1145,7 +1148,7 @@ class DatabaseOperations:
|
|
|
1145
1148
|
print(f"Deleted {deleted_count} records.")
|
|
1146
1149
|
```
|
|
1147
1150
|
"""
|
|
1148
|
-
if id_values is None:
|
|
1151
|
+
if id_values is None: #pragma: no cover
|
|
1149
1152
|
id_values = []
|
|
1150
1153
|
try:
|
|
1151
1154
|
# Start a timer to measure the operation time
|
|
@@ -45,6 +45,10 @@ print(get_month_number('January'))
|
|
|
45
45
|
|
|
46
46
|
This module is part of the dsg_lib package and is used for handling and
|
|
47
47
|
converting between month numbers and names.
|
|
48
|
+
|
|
49
|
+
Author: Mike Ryan
|
|
50
|
+
Date: 2024/05/16
|
|
51
|
+
License: MIT
|
|
48
52
|
"""
|
|
49
53
|
from loguru import logger
|
|
50
54
|
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
# -*- 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
|
+
"""
|
|
39
|
+
from enum import Enum
|
|
40
|
+
from typing import Dict, List, Union
|
|
41
|
+
from loguru import logger
|
|
42
|
+
from email_validator import (
|
|
43
|
+
EmailNotValidError,
|
|
44
|
+
EmailUndeliverableError,
|
|
45
|
+
caching_resolver,
|
|
46
|
+
validate_email,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
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
|
+
"""
|
|
60
|
+
DNS = "dns"
|
|
61
|
+
TIMEOUT = "timeout"
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def validate_email_address(
|
|
65
|
+
email: str,
|
|
66
|
+
check_deliverability: bool = True,
|
|
67
|
+
test_environment: bool = False,
|
|
68
|
+
allow_smtputf8: bool = False,
|
|
69
|
+
allow_empty_local: bool = False,
|
|
70
|
+
allow_quoted_local:bool=False,
|
|
71
|
+
allow_display_name: bool = False,
|
|
72
|
+
allow_domain_literal: bool = False,
|
|
73
|
+
globally_deliverable: bool = None,
|
|
74
|
+
timeout: int = 10,
|
|
75
|
+
dns_type: str = 'dns',
|
|
76
|
+
) -> 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.
|
|
81
|
+
|
|
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
|
|
105
|
+
logger.debug(f"validate_email_address: {email} with params: {locals()}")
|
|
106
|
+
|
|
107
|
+
# Initialize the valid flag to False
|
|
108
|
+
valid: bool = False
|
|
109
|
+
|
|
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.")
|
|
115
|
+
|
|
116
|
+
# Set up the DNS resolver based on the dns_type
|
|
117
|
+
if dns_type == DNSType.DNS:
|
|
118
|
+
dns_resolver = caching_resolver(timeout=timeout)
|
|
119
|
+
dns_param = {"dns_resolver": dns_resolver}
|
|
120
|
+
elif dns_type == DNSType.TIMEOUT:
|
|
121
|
+
if timeout is None or timeout <= 0 or isinstance(timeout, int) is False:
|
|
122
|
+
timeout = 5
|
|
123
|
+
dns_param = {"timeout": timeout}
|
|
124
|
+
|
|
125
|
+
# Validate the email address
|
|
126
|
+
try:
|
|
127
|
+
emailinfo = validate_email(
|
|
128
|
+
email,
|
|
129
|
+
check_deliverability=check_deliverability,
|
|
130
|
+
test_environment=test_environment,
|
|
131
|
+
allow_smtputf8=allow_smtputf8,
|
|
132
|
+
allow_empty_local=allow_empty_local,
|
|
133
|
+
allow_domain_literal=allow_domain_literal,
|
|
134
|
+
globally_deliverable=globally_deliverable,
|
|
135
|
+
**dns_param,
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
# Normalize the email address
|
|
139
|
+
email: str = emailinfo.normalized
|
|
140
|
+
|
|
141
|
+
# Initialize the return dictionary
|
|
142
|
+
email_dict: Dict[
|
|
143
|
+
str, Union[str, bool, Dict[str, Union[str, bool, List[str]]]]
|
|
144
|
+
] = {
|
|
145
|
+
"email": email,
|
|
146
|
+
"valid": valid,
|
|
147
|
+
"email_data": None,
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# Check the deliverability of the email address
|
|
151
|
+
if not check_deliverability or emailinfo.mx is not None:
|
|
152
|
+
email_dict["valid"] = True
|
|
153
|
+
logger.info(f"Email is valid: {email}")
|
|
154
|
+
else: # pragma: no cover
|
|
155
|
+
email_dict["valid"] = False
|
|
156
|
+
logger.info(f"Email invalid: {email}")
|
|
157
|
+
|
|
158
|
+
# Add the email info and parameters to the return dictionary
|
|
159
|
+
email_dict["email_data"] = dict(sorted(vars(emailinfo).items()))
|
|
160
|
+
email_dict["parameters"]=dict(sorted(locals().items()))
|
|
161
|
+
|
|
162
|
+
# Print and return the dictionary
|
|
163
|
+
print(email_dict)
|
|
164
|
+
return email_dict
|
|
165
|
+
|
|
166
|
+
# Handle EmailUndeliverableError
|
|
167
|
+
except EmailUndeliverableError as e:
|
|
168
|
+
error = str(e)
|
|
169
|
+
parameters=dict(sorted(locals().items()))
|
|
170
|
+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "EmailUndeliverableError","parameters":parameters}
|
|
171
|
+
logger.error(f"EmailUndeliverableError: {email} - {str(e)}")
|
|
172
|
+
logger.debug(f"EmailUndeliverableError: {email} - {str(e)}, - {parameters}")
|
|
173
|
+
return email_dict
|
|
174
|
+
|
|
175
|
+
# Handle EmailNotValidError
|
|
176
|
+
except EmailNotValidError as e:
|
|
177
|
+
error = str(e)
|
|
178
|
+
parameters=dict(sorted(locals().items()))
|
|
179
|
+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "EmailNotValidError","parameters":parameters}
|
|
180
|
+
logger.error(f"EmailNotValidError: {email} - {str(e)}")
|
|
181
|
+
logger.debug(f"EmailNotValidError: {email} - {str(e)}, - {parameters}")
|
|
182
|
+
return email_dict
|
|
183
|
+
|
|
184
|
+
# Handle other exceptions
|
|
185
|
+
except Exception as e: # pragma: no cover
|
|
186
|
+
error = str(e)
|
|
187
|
+
parameters=dict(sorted(locals().items()))
|
|
188
|
+
email_dict = {"valid": False, "email": email, "error": error,"error_type": "Exception","parameters":parameters}
|
|
189
|
+
logger.error(f"Exception: {email} - {str(e)}")
|
|
190
|
+
logger.debug(f"Exception: {email} - {str(e)}, - {parameters}")
|
|
191
|
+
return email_dict
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
if __name__ == "__main__":
|
|
195
|
+
# create a list of email addresses to check if valid
|
|
196
|
+
email_addresses = [
|
|
197
|
+
"bob@devsetgo.com",
|
|
198
|
+
"bob@devset.go",
|
|
199
|
+
"foo@yahoo.com",
|
|
200
|
+
"bob@gmail.com",
|
|
201
|
+
"very fake@devsetgo.com",
|
|
202
|
+
"jane.doe@example.com",
|
|
203
|
+
"john_doe@example.co.uk",
|
|
204
|
+
"user.name+tag+sorting@example.com",
|
|
205
|
+
"x@example.com", # shortest possible email address
|
|
206
|
+
"example-indeed@strange-example.com",
|
|
207
|
+
"admin@mailserver1", # local domain name with no TLD
|
|
208
|
+
"example@s.example", # see the list of Internet top-level domains
|
|
209
|
+
'" "@example.org', # space between the quotes
|
|
210
|
+
'"john..doe"@example.org', # quoted double dot
|
|
211
|
+
"mailhost!username@example.org", # bangified host route used for uucp mailers
|
|
212
|
+
"user%example.com@example.org", # percent sign in local part
|
|
213
|
+
"user-@example.org", # valid due to the last character being an allowed character
|
|
214
|
+
# Invalid email addresses
|
|
215
|
+
"Abc.example.com", # no @ character
|
|
216
|
+
"A@b@c@example.com", # only one @ is allowed outside quotation marks
|
|
217
|
+
'a"b(c)d,e:f;g<h>i[j\\k]l@example.com', # none of the special characters in this local part are allowed outside quotation marks
|
|
218
|
+
'just"not"right@example.com', # quoted strings must be dot separated or the only element making up the local-part
|
|
219
|
+
'this is"not\\allowed@example.com', # spaces, quotes, and backslashes may only exist when within quoted strings and preceded by a backslash
|
|
220
|
+
'this\\ still\\"not\\\\allowed@example.com', # even if escaped (preceded by a backslash), spaces, quotes, and backslashes must still be contained by quotes
|
|
221
|
+
"1234567890123456789012345678901234567890123456789012345678901234+x@example.com", # local part is longer than 64 characters
|
|
222
|
+
|
|
223
|
+
# Emails with empty local part
|
|
224
|
+
"@example.com", # only valid if allow_empty_local is True
|
|
225
|
+
|
|
226
|
+
# Emails with non-ASCII characters
|
|
227
|
+
"üñîçøðé@example.com", # only valid if allow_smtputf8 is True
|
|
228
|
+
"user@üñîçøðé.com", # only valid if allow_smtputf8 is True
|
|
229
|
+
|
|
230
|
+
# Emails with quoted local part
|
|
231
|
+
'"john.doe"@example.com', # only valid if allow_quoted_local is True
|
|
232
|
+
'"john..doe"@example.com', # only valid if allow_quoted_local is True
|
|
233
|
+
|
|
234
|
+
# Emails with display name
|
|
235
|
+
'John Doe <john@example.com>', # only valid if allow_display_name is True
|
|
236
|
+
|
|
237
|
+
# Emails with domain literal
|
|
238
|
+
'user@[192.0.2.1]', # only valid if allow_domain_literal is True
|
|
239
|
+
|
|
240
|
+
# Emails with long local part
|
|
241
|
+
"a"*65 + "@example.com", # local part is longer than 64 characters
|
|
242
|
+
|
|
243
|
+
# Emails with invalid characters
|
|
244
|
+
"john doe@example.com", # space is not allowed
|
|
245
|
+
"john@doe@example.com", # only one @ is allowed
|
|
246
|
+
"john.doe@.com", # domain can't start with a dot
|
|
247
|
+
"john.doe@example..com", # domain can't have two consecutive dots
|
|
248
|
+
"test@google.com",
|
|
249
|
+
]
|
|
250
|
+
|
|
251
|
+
# create a list of configurations
|
|
252
|
+
configurations = [
|
|
253
|
+
{"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'},
|
|
254
|
+
{"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'},
|
|
255
|
+
{"check_deliverability": True},
|
|
256
|
+
# add more configurations here
|
|
257
|
+
]
|
|
258
|
+
|
|
259
|
+
import pprint
|
|
260
|
+
import time
|
|
261
|
+
|
|
262
|
+
t0 = time.time()
|
|
263
|
+
validity=[]
|
|
264
|
+
|
|
265
|
+
for email in email_addresses:
|
|
266
|
+
for config in configurations:
|
|
267
|
+
|
|
268
|
+
res = validate_email_address(email, **config)
|
|
269
|
+
validity.append(res)
|
|
270
|
+
t1 = time.time()
|
|
271
|
+
validity = sorted(validity, key=lambda x: x['email'])
|
|
272
|
+
|
|
273
|
+
for v in validity:
|
|
274
|
+
pprint.pprint(v, indent=4)
|
|
275
|
+
|
|
276
|
+
print(f"Time taken: {t1 - t0:.2f}")
|
|
@@ -31,7 +31,12 @@ folder_functions.remove_folder("/path/to/directory/old_folder") # Removes the
|
|
|
31
31
|
folder at '/path/to/directory/old_folder'
|
|
32
32
|
|
|
33
33
|
```
|
|
34
|
+
|
|
35
|
+
Author: Mike Ryan
|
|
36
|
+
Date: 2024/05/16
|
|
37
|
+
License: MIT
|
|
34
38
|
"""
|
|
39
|
+
|
|
35
40
|
import re
|
|
36
41
|
from datetime import datetime
|
|
37
42
|
from pathlib import Path
|
|
@@ -23,6 +23,10 @@ Attributes:
|
|
|
23
23
|
ALL_HTTP_CODES (dict): A dictionary of HTTP status codes. Each key is an
|
|
24
24
|
HTTP status code (int), and each value is another dictionary with keys
|
|
25
25
|
'description' (str), 'extended_description' (str), and 'link' (str).
|
|
26
|
+
|
|
27
|
+
Author: Mike Ryan
|
|
28
|
+
Date: 2024/05/16
|
|
29
|
+
License: MIT
|
|
26
30
|
"""
|
|
27
31
|
from loguru import logger
|
|
28
32
|
|
{devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/system_health_endpoints.py
RENAMED
|
@@ -62,6 +62,10 @@ Example:
|
|
|
62
62
|
# {"memory_use":{"current": "123456", "peak": "789012"}, "heap_dump": [{"filename": "main.py", "lineno": 10, "size": 1234, "count": 1}, ...]}
|
|
63
63
|
|
|
64
64
|
```
|
|
65
|
+
|
|
66
|
+
Author: Mike Ryan
|
|
67
|
+
Date: 2024/05/16
|
|
68
|
+
License: MIT
|
|
65
69
|
"""
|
|
66
70
|
|
|
67
71
|
# Import necessary modules
|
|
@@ -8,7 +8,7 @@ build-backend = "hatchling.build"
|
|
|
8
8
|
|
|
9
9
|
[project]
|
|
10
10
|
name = "devsetgo_lib"
|
|
11
|
-
version = "0.12.
|
|
11
|
+
version = "0.12.4"
|
|
12
12
|
requires-python = ">=3.9"
|
|
13
13
|
description = "DevSetGo Common Library provides reusable Python functions for enhanced code efficiency. It includes utilities for file operations, calendar, pattern matching, logging, FastAPI endpoints, and async database handling with CRUD operations."
|
|
14
14
|
readme = "README.md"
|
|
@@ -34,6 +34,7 @@ classifiers = [
|
|
|
34
34
|
dependencies = [
|
|
35
35
|
"loguru>=0.7.0",
|
|
36
36
|
"packaging>=20.0",
|
|
37
|
+
"email-validator>=2.1.1"
|
|
37
38
|
]
|
|
38
39
|
# loguru = ">=0.7.0"
|
|
39
40
|
# packaging = ">=20.0"
|
|
@@ -86,20 +87,23 @@ unsafe-fixes = true
|
|
|
86
87
|
# Assume Python 3.8
|
|
87
88
|
target-version = "py312"
|
|
88
89
|
src = ["dsg_lib", "test"]
|
|
89
|
-
exclude = ["unreleased/*","
|
|
90
|
+
exclude = ["unreleased/*","scripts/*","coverage.xml","coverage-badge.svg"] #,"examples/*"
|
|
91
|
+
|
|
92
|
+
[tool.ruff.lint]
|
|
90
93
|
select = [
|
|
91
94
|
"C", # mccabe rules
|
|
92
95
|
"F", # pyflakes rules
|
|
93
96
|
"E", # pycodestyle error rules
|
|
94
97
|
"W", # pycodestyle warning rules
|
|
95
98
|
"B", # flake8-bugbear rules
|
|
96
|
-
"I", # isort rules
|
|
97
99
|
]
|
|
98
100
|
ignore = [
|
|
99
101
|
"C901", # max-complexity-10
|
|
100
102
|
"E501", # line-too-long
|
|
101
103
|
"B017",
|
|
102
|
-
"B904"
|
|
104
|
+
"B904",
|
|
105
|
+
"B008",
|
|
106
|
+
"I", # isort rules
|
|
103
107
|
]
|
|
104
108
|
|
|
105
109
|
[tool.ruff.format]
|
|
@@ -134,7 +138,7 @@ multi_line_output = 3
|
|
|
134
138
|
include_trailing_comma = true
|
|
135
139
|
force_grid_wrap = 0
|
|
136
140
|
use_parentheses = true
|
|
137
|
-
line_length =
|
|
141
|
+
line_length = 100
|
|
138
142
|
|
|
139
143
|
[tool.coverage.run]
|
|
140
144
|
source = ["dsg_lib"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|