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.
Files changed (23) hide show
  1. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/PKG-INFO +14 -6
  2. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/README.md +12 -5
  3. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/__init__.py +1 -1
  4. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/__import_sqlalchemy.py +3 -0
  5. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/async_database.py +4 -0
  6. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/base_schema.py +4 -0
  7. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_config.py +4 -0
  8. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/database_operations.py +6 -3
  9. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/calendar_functions.py +4 -0
  10. devsetgo_lib-0.12.4/dsg_lib/common_functions/email_validation.py +276 -0
  11. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/file_functions.py +4 -0
  12. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/folder_functions.py +5 -0
  13. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/logging_config.py +4 -0
  14. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/patterns.py +4 -0
  15. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/_all_codes.py +4 -0
  16. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/http_codes.py +4 -0
  17. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/fastapi_functions/system_health_endpoints.py +4 -0
  18. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/pyproject.toml +9 -5
  19. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/.gitignore +0 -0
  20. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/LICENSE +0 -0
  21. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/async_database_functions/__init__.py +0 -0
  22. {devsetgo_lib-0.12.2 → devsetgo_lib-0.12.4}/dsg_lib/common_functions/__init__.py +0 -0
  23. {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.2
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
  [![PyPI version fury.io](https://badge.fury.io/py/devsetgo-lib.svg)](https://pypi.python.org/pypi/devsetgo-lib/)
74
- <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg">
75
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib)](https://pepy.tech/project/devsetgo-lib)
76
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib/month)](https://pepy.tech/project/devsetgo-lib)
77
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib/week)](https://pepy.tech/project/devsetgo-lib)
78
+
79
+ Support Python Versions
80
+
81
+ ![Static Badge](https://img.shields.io/badge/Python-3.12%20%7C%203.11%20%7C%203.10%20%7C%203.9-blue)
82
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
75
83
 
76
- [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/)
77
- [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)
78
- [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
79
- [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
80
84
 
81
85
  CI/CD Pipeline:
82
86
 
83
87
  [![Testing - Main](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
84
88
  [![Testing - Dev](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml/badge.svg?branch=dev)](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
89
+ [![Coverage fury.io](coverage-badge.svg)](https://github.com/devsetgo/dsg_lib)
85
90
 
86
91
  SonarCloud:
87
92
 
@@ -92,6 +97,9 @@ SonarCloud:
92
97
  [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=devsetgo_devsetgo_lib&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
93
98
  [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=devsetgo_devsetgo_lib&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
94
99
 
100
+ ![Static Badge](https://img.shields.io/badge/Documentation-v0.12.2-blue?link=https%3A%2F%2Fdevsetgo.github.io%2Fdevsetgo_lib)
101
+
102
+
95
103
  # DevSetGo Common Library
96
104
 
97
105
  ## Introduction
@@ -1,17 +1,21 @@
1
1
  Python:
2
2
 
3
3
  [![PyPI version fury.io](https://badge.fury.io/py/devsetgo-lib.svg)](https://pypi.python.org/pypi/devsetgo-lib/)
4
- <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg">
4
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib)](https://pepy.tech/project/devsetgo-lib)
5
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib/month)](https://pepy.tech/project/devsetgo-lib)
6
+ [![Downloads](https://static.pepy.tech/badge/devsetgo-lib/week)](https://pepy.tech/project/devsetgo-lib)
7
+
8
+ Support Python Versions
9
+
10
+ ![Static Badge](https://img.shields.io/badge/Python-3.12%20%7C%203.11%20%7C%203.10%20%7C%203.9-blue)
11
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
5
12
 
6
- [![Python 3.9](https://img.shields.io/badge/python-3.9-blue.svg)](https://www.python.org/downloads/release/python-390/)
7
- [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)
8
- [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
9
- [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
10
13
 
11
14
  CI/CD Pipeline:
12
15
 
13
16
  [![Testing - Main](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml/badge.svg?branch=main)](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
14
17
  [![Testing - Dev](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml/badge.svg?branch=dev)](https://github.com/devsetgo/devsetgo_lib/actions/workflows/testing.yml)
18
+ [![Coverage fury.io](coverage-badge.svg)](https://github.com/devsetgo/dsg_lib)
15
19
 
16
20
  SonarCloud:
17
21
 
@@ -22,6 +26,9 @@ SonarCloud:
22
26
  [![Reliability Rating](https://sonarcloud.io/api/project_badges/measure?project=devsetgo_devsetgo_lib&metric=reliability_rating)](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
23
27
  [![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=devsetgo_devsetgo_lib&metric=vulnerabilities)](https://sonarcloud.io/dashboard?id=devsetgo_devsetgo_lib)
24
28
 
29
+ ![Static Badge](https://img.shields.io/badge/Documentation-v0.12.2-blue?link=https%3A%2F%2Fdevsetgo.github.io%2Fdevsetgo_lib)
30
+
31
+
25
32
  # DevSetGo Common Library
26
33
 
27
34
  ## Introduction
@@ -1,3 +1,3 @@
1
1
  # -*- coding: utf-8 -*-
2
2
 
3
- __version__ = '0.12.2'
3
+ __version__ = '0.12.4'
@@ -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
 
@@ -43,6 +43,10 @@ async_db = async_database.AsyncDatabase(db_config)
43
43
  # Create a DatabaseOperations instance
44
44
  db_ops = database_operations.DatabaseOperations(async_db)
45
45
  ```
46
+
47
+ Author: Mike Ryan
48
+ Date: 2024/05/16
49
+ License: MIT
46
50
  """
47
51
 
48
52
 
@@ -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
@@ -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
@@ -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,6 +31,10 @@ file_functions.delete_file("test.csv")
31
31
 
32
32
  # Outputs: 'complete'
33
33
  ```
34
+
35
+ Author: Mike Ryan
36
+ Date: 2024/05/16
37
+ License: MIT
34
38
  """
35
39
 
36
40
  # Import required modules
@@ -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
@@ -30,6 +30,10 @@ logger.error("This is an error message")
30
30
  logger.warning("This is a warning message")
31
31
  logger.critical("This is a critical message")
32
32
  ```
33
+
34
+ Author: Mike Ryan
35
+ Date: 2024/05/16
36
+ License: MIT
33
37
  """
34
38
 
35
39
  import logging
@@ -33,6 +33,10 @@ Example:
33
33
  }
34
34
  ```
35
35
 
36
+ Author: Mike Ryan
37
+ Date: 2024/05/16
38
+ License: MIT
39
+
36
40
  """
37
41
  import re
38
42
 
@@ -31,6 +31,10 @@ Example:
31
31
  link_500 = ALL_HTTP_CODES[500]['link']
32
32
  print(link_500) # Output: 'https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500'
33
33
  ```
34
+
35
+ Author: Mike Ryan
36
+ Date: 2024/05/16
37
+ License: MIT
34
38
  """
35
39
 
36
40
  ALL_HTTP_CODES = {
@@ -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
 
@@ -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.2"
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/*","examples/*","scripts/*"]
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 = 88
141
+ line_length = 100
138
142
 
139
143
  [tool.coverage.run]
140
144
  source = ["dsg_lib"]
File without changes
File without changes