From 30b1ca6c523c0778ca99d01651c34a8478aeda6c Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 11:18:58 +0530 Subject: [PATCH 01/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 36 +++++++++++++++++++++++ sendgrid/base_interface.py | 30 +++++++++++++++++-- sendgrid/sendgrid.py | 8 ++++-- test/unit/test_sendgrid.py | 43 ++++++++++++++++++++++++++++ 4 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 examples/dataresidency/set_region.py create mode 100644 test/unit/test_sendgrid.py diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py new file mode 100644 index 000000000..e4cae4c98 --- /dev/null +++ b/examples/dataresidency/set_region.py @@ -0,0 +1,36 @@ +import sendgrid +import os + +from sendgrid import Email, To, Content, Mail + +# Example 1 +# setting region to be "global" +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) +sg.set_region("global") +from_email = Email("example@abc.com") +to_email = To("example@abc.com") +subject = "Sending with SendGrid is Fun" +content = Content("text/plain", "and easy to do anywhere, even with Python") +print(sg.host) +mail = Mail(from_email, to_email, subject, content) +response = sg.client.mail.send.post(request_body=mail.get()) +print(response) +print(response.status_code) +print(response.body) +print(response.headers) + +# Example 2 +# setting region to "eu" +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) +sg.set_region("eu") +from_email = Email("example@abc.com") +to_email = To("example@abc.com") +subject = "Sending with SendGrid is Fun" +content = Content("text/plain", "and easy to do anywhere, even with Python") +print(sg.host) +mail = Mail(from_email, to_email, subject, content) +response = sg.client.mail.send.post(request_body=mail.get()) +print(response) +print(response.status_code) +print(response.body) +print(response.headers) \ No newline at end of file diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 92b38247e..99e0eb780 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -2,7 +2,7 @@ class BaseInterface(object): - def __init__(self, auth, host, impersonate_subuser): + def __init__(self, auth, host, region, impersonate_subuser): """ Construct the Twilio SendGrid v3 API object. Note that the underlying client is being set up during initialization, @@ -19,10 +19,15 @@ def __init__(self, auth, host, impersonate_subuser): :type impersonate_subuser: string :param host: base URL for API calls :type host: string + :param region: To determine the region which can only be 'global' or 'eu' + :type region: string """ from . import __version__ self.auth = auth - self.host = host + if host is not None and region == 'global': + self.set_host(host) + else: + self.set_region(region) self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) @@ -60,3 +65,24 @@ def send(self, message): message = message.get() return self.client.mail.send.post(request_body=message) + + def set_host(self,host): + self.host = host + + def set_region(self,region): + """ + * Client libraries contain setters for specifying region/edge. + * This allows support global and eu regions only. This set will likely expand in the future. + * Global should be the default + * Global region means the message should be sent through: + * HTTP: api.sendgrid.com + * EU region means the message should be sent through: + * HTTP: api.eu.sendgrid.com + :param region: + :return: + """ + region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} + if region in region_host_dict.keys(): + self.host = region_host_dict[region] + else: + raise ValueError("region can only be \"eu\" or \"global\"") diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 912d8336e..9eb9ffad0 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -32,7 +32,8 @@ class SendGridAPIClient(BaseInterface): def __init__( self, api_key=None, - host='https://api.sendgrid.com', + host=None, + region='global', impersonate_subuser=None): """ Construct the Twilio SendGrid v3 API object. @@ -51,8 +52,11 @@ def __init__( :type impersonate_subuser: string :param host: base URL for API calls :type host: string + :param region: To determine the region which can only be 'global' or 'eu' + :type region: string """ self.api_key = api_key or os.environ.get('SENDGRID_API_KEY') auth = 'Bearer {}'.format(self.api_key) - super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser) + super(SendGridAPIClient, self).__init__(auth, host, region, impersonate_subuser) + diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py new file mode 100644 index 000000000..ac104564b --- /dev/null +++ b/test/unit/test_sendgrid.py @@ -0,0 +1,43 @@ +import unittest +import sendgrid + +class UnitTests(unittest.TestCase): + def test_host_with_no_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + self.assertEqual("https://api.sendgrid.com",sg.host) + + def test_host_with_eu_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("eu") + self.assertEqual("https://api.eu.sendgrid.com",sg.host) + + def test_host_with_global_region(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("global") + self.assertEqual("https://api.sendgrid.com",sg.host) + + def test_host_with_host_first_eu_region_second(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_host("https://sendgrid.com") + sg.set_region("eu") + self.assertEqual("https://api.eu.sendgrid.com",sg.host) + + def test_host_with_eu_first_host_second(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + sg.set_region("eu") + sg.set_host("https://sendgrid.com") + self.assertEqual("https://sendgrid.com",sg.host) + + def test_host_using_constructor(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host='https://sendgrid.com') + self.assertEqual("https://sendgrid.com",sg.host) + + def test_with_region_is_none(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + with self.assertRaises(ValueError): + sg.set_region("") + + def test_with_region_is_none(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') + with self.assertRaises(ValueError): + sg.set_region("abc") \ No newline at end of file From 1e1299da0d364efc910f71f43cf5547deeb24b16 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 13:24:14 +0530 Subject: [PATCH 02/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- sendgrid/base_interface.py | 2 +- sendgrid/sendgrid.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 99e0eb780..5c2bd365e 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -2,7 +2,7 @@ class BaseInterface(object): - def __init__(self, auth, host, region, impersonate_subuser): + def __init__(self, auth, host, impersonate_subuser, region='global'): """ Construct the Twilio SendGrid v3 API object. Note that the underlying client is being set up during initialization, diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 9eb9ffad0..22ccf6e32 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -58,5 +58,5 @@ def __init__( self.api_key = api_key or os.environ.get('SENDGRID_API_KEY') auth = 'Bearer {}'.format(self.api_key) - super(SendGridAPIClient, self).__init__(auth, host, region, impersonate_subuser) + super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser,region) From 9d433a698443b1e6e9e1fc94747a131ad00f427f Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 15:11:43 +0530 Subject: [PATCH 03/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 1 - sendgrid/base_interface.py | 6 +++--- test/unit/test_sendgrid.py | 14 +++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index e4cae4c98..c93d48b24 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -1,5 +1,4 @@ import sendgrid -import os from sendgrid import Email, To, Content, Mail diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 5c2bd365e..697cf6c3f 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -1,5 +1,6 @@ import python_http_client +region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} class BaseInterface(object): def __init__(self, auth, host, impersonate_subuser, region='global'): @@ -27,7 +28,7 @@ def __init__(self, auth, host, impersonate_subuser, region='global'): if host is not None and region == 'global': self.set_host(host) else: - self.set_region(region) + self.set_data_residency(region) self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) @@ -69,7 +70,7 @@ def send(self, message): def set_host(self,host): self.host = host - def set_region(self,region): + def set_data_residency(self,region): """ * Client libraries contain setters for specifying region/edge. * This allows support global and eu regions only. This set will likely expand in the future. @@ -81,7 +82,6 @@ def set_region(self,region): :param region: :return: """ - region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} if region in region_host_dict.keys(): self.host = region_host_dict[region] else: diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py index ac104564b..d5185a093 100644 --- a/test/unit/test_sendgrid.py +++ b/test/unit/test_sendgrid.py @@ -8,23 +8,23 @@ def test_host_with_no_region(self): def test_host_with_eu_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_region("eu") + sg.set_data_residency("eu") self.assertEqual("https://api.eu.sendgrid.com",sg.host) def test_host_with_global_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_region("global") + sg.set_data_residency("global") self.assertEqual("https://api.sendgrid.com",sg.host) def test_host_with_host_first_eu_region_second(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') sg.set_host("https://sendgrid.com") - sg.set_region("eu") + sg.set_data_residency("eu") self.assertEqual("https://api.eu.sendgrid.com",sg.host) def test_host_with_eu_first_host_second(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_region("eu") + sg.set_data_residency("eu") sg.set_host("https://sendgrid.com") self.assertEqual("https://sendgrid.com",sg.host) @@ -35,9 +35,9 @@ def test_host_using_constructor(self): def test_with_region_is_none(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_region("") + sg.set_data_residency(None) - def test_with_region_is_none(self): + def test_with_region_is_invalid(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_region("abc") \ No newline at end of file + sg.set_data_residency("abc") \ No newline at end of file From bb9535f0987f252d70b107648a65f6b11fa934b0 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 15:40:15 +0530 Subject: [PATCH 04/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index 1c5f53f23..c1383347b 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff --format=github --ignore="E722,F40,F841" --line-length=681 --target-version=py37 . + - run: ruff format=github --ignore="E722,F40,F841" --line-length=681 --target-version=py37 . From b81337d73a90ac96c1e99858ba5a9823feb38f3b Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 15:49:10 +0530 Subject: [PATCH 05/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- examples/dataresidency/set_region.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index c1383347b..ba6d3ca9d 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff format=github --ignore="E722,F40,F841" --line-length=681 --target-version=py37 . + - run: ruff format=github --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index c93d48b24..e4cae4c98 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -1,4 +1,5 @@ import sendgrid +import os from sendgrid import Email, To, Content, Mail From 7e5604924daca8b1e8d577ce42911ff7e0e691a2 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 16:28:00 +0530 Subject: [PATCH 06/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index ba6d3ca9d..ace47f77d 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff format=github --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . + - run: ruff --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . From e7b9578b7284418784625364c93893f108b00034 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 16:28:29 +0530 Subject: [PATCH 07/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index ace47f77d..5e1d5081f 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . + - run: ruff format --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . From 3bd6d6f2567801be0c153b47aa3bf106b4e06f31 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 16:33:37 +0530 Subject: [PATCH 08/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index 5e1d5081f..322f0e1d3 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff format --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . + - run: ruff -- --format=github --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . From cf2cc5d1f062a75ad1c69e82d57fa750f3cb8364 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 16:39:32 +0530 Subject: [PATCH 09/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index 322f0e1d3..aa283ee62 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff -- --format=github --ignore="E722,F40,F841" --line-length=320 --target-version=py37 . + - run: ruff -- --format=github --ignore="E722,F40,F841,F405,F401" --line-length=320 --target-version=py37 . From 401902468d0a434e43b970c33c0965e7685ca0ec Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Tue, 14 Nov 2023 16:43:43 +0530 Subject: [PATCH 10/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index aa283ee62..1c5f53f23 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff -- --format=github --ignore="E722,F40,F841,F405,F401" --line-length=320 --target-version=py37 . + - run: ruff --format=github --ignore="E722,F40,F841" --line-length=681 --target-version=py37 . From 6ceb5246aa27229c8fb646397277a8e86dc48072 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 16 Nov 2023 13:22:13 +0530 Subject: [PATCH 11/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 12 ++++++++---- sendgrid/base_interface.py | 13 +++++++++---- sendgrid/sendgrid.py | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index e4cae4c98..935fbaaa7 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -5,8 +5,10 @@ # Example 1 # setting region to be "global" -sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg.set_region("global") +# sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) + +sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY')) +sg.set_data_residency("global") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" @@ -19,10 +21,12 @@ print(response.body) print(response.headers) + # Example 2 # setting region to "eu" -sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg.set_region("eu") +sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY')) +sg.set_host("https://api.eu.sendgrid.com") +# sg.set_data_residency("eu") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 697cf6c3f..f2b52d168 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -25,10 +25,7 @@ def __init__(self, auth, host, impersonate_subuser, region='global'): """ from . import __version__ self.auth = auth - if host is not None and region == 'global': - self.set_host(host) - else: - self.set_data_residency(region) + self.host = host self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) @@ -69,6 +66,10 @@ def send(self, message): def set_host(self,host): self.host = host + self.client = python_http_client.Client( + host=self.host, + request_headers=self._default_headers, + version=3) def set_data_residency(self,region): """ @@ -84,5 +85,9 @@ def set_data_residency(self,region): """ if region in region_host_dict.keys(): self.host = region_host_dict[region] + self.client = python_http_client.Client( + host=self.host, + request_headers=self._default_headers, + version=3) else: raise ValueError("region can only be \"eu\" or \"global\"") diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 22ccf6e32..7e53a5e1e 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -32,7 +32,7 @@ class SendGridAPIClient(BaseInterface): def __init__( self, api_key=None, - host=None, + host='https://api.sendgrid.com', region='global', impersonate_subuser=None): """ From 2a9930f28c086e34e544d530c7a45bedd841147d Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 16 Nov 2023 13:47:12 +0530 Subject: [PATCH 12/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index 935fbaaa7..394109b5e 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -7,13 +7,13 @@ # setting region to be "global" # sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY')) +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) sg.set_data_residency("global") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" content = Content("text/plain", "and easy to do anywhere, even with Python") -print(sg.host) +print(sg.client.host) mail = Mail(from_email, to_email, subject, content) response = sg.client.mail.send.post(request_body=mail.get()) print(response) @@ -23,15 +23,30 @@ # Example 2 -# setting region to "eu" -sg = sendgrid.SendGridAPIClient(os.environ.get('SENDGRID_API_KEY')) +# setting host +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) sg.set_host("https://api.eu.sendgrid.com") -# sg.set_data_residency("eu") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" content = Content("text/plain", "and easy to do anywhere, even with Python") -print(sg.host) +print(sg.client.host) +mail = Mail(from_email, to_email, subject, content) +response = sg.client.mail.send.post(request_body=mail.get()) +print(response) +print(response.status_code) +print(response.body) +print(response.headers) + +# Example 3 +# setting region to "eu" +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) +sg.set_data_residency("eu") +from_email = Email("example@abc.com") +to_email = To("example@abc.com") +subject = "Sending with SendGrid is Fun" +content = Content("text/plain", "and easy to do anywhere, even with Python") +print(sg.client.host) mail = Mail(from_email, to_email, subject, content) response = sg.client.mail.send.post(request_body=mail.get()) print(response) From 58859857b98588c51bcad3aae7c9ae732805ec6a Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 16 Nov 2023 13:59:07 +0530 Subject: [PATCH 13/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- test/unit/test_sendgrid.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py index d5185a093..1815d43a5 100644 --- a/test/unit/test_sendgrid.py +++ b/test/unit/test_sendgrid.py @@ -4,33 +4,33 @@ class UnitTests(unittest.TestCase): def test_host_with_no_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - self.assertEqual("https://api.sendgrid.com",sg.host) + self.assertEqual("https://api.sendgrid.com",sg.client.host) def test_host_with_eu_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') sg.set_data_residency("eu") - self.assertEqual("https://api.eu.sendgrid.com",sg.host) + self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) def test_host_with_global_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') sg.set_data_residency("global") - self.assertEqual("https://api.sendgrid.com",sg.host) + self.assertEqual("https://api.sendgrid.com",sg.client.host) def test_host_with_host_first_eu_region_second(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') sg.set_host("https://sendgrid.com") sg.set_data_residency("eu") - self.assertEqual("https://api.eu.sendgrid.com",sg.host) + self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) def test_host_with_eu_first_host_second(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') sg.set_data_residency("eu") sg.set_host("https://sendgrid.com") - self.assertEqual("https://sendgrid.com",sg.host) + self.assertEqual("https://sendgrid.com",sg.client.host) def test_host_using_constructor(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host='https://sendgrid.com') - self.assertEqual("https://sendgrid.com",sg.host) + self.assertEqual("https://sendgrid.com",sg.client.host) def test_with_region_is_none(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') From 3dc77d82bcbafac4e898bd6f76b51b27bcef6253 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Mon, 20 Nov 2023 14:39:58 +0530 Subject: [PATCH 14/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 1 - sendgrid/base_interface.py | 30 +++++++++++++++------------- sendgrid/sendgrid.py | 2 +- test/unit/test_sendgrid.py | 6 +++++- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index 394109b5e..aa3d6aa9b 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -5,7 +5,6 @@ # Example 1 # setting region to be "global" -# sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) sg.set_data_residency("global") diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index f2b52d168..86ed18cab 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -25,10 +25,13 @@ def __init__(self, auth, host, impersonate_subuser, region='global'): """ from . import __version__ self.auth = auth - self.host = host self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) + if region is None: + self.host = host + else: + self.set_data_residency(region=region) self.client = python_http_client.Client( host=self.host, @@ -64,30 +67,29 @@ def send(self, message): return self.client.mail.send.post(request_body=message) - def set_host(self,host): + def set_host(self, host): self.host = host self.client = python_http_client.Client( host=self.host, request_headers=self._default_headers, version=3) - def set_data_residency(self,region): + def set_data_residency(self, region): """ - * Client libraries contain setters for specifying region/edge. - * This allows support global and eu regions only. This set will likely expand in the future. - * Global should be the default - * Global region means the message should be sent through: - * HTTP: api.sendgrid.com - * EU region means the message should be sent through: - * HTTP: api.eu.sendgrid.com + Client libraries contain setters for specifying region/edge. + This supports global and eu regions only. This set will likely expand in the future. + Global is the default residency (or region) + Global region means the message will be sent through https://api.sendgrid.com + EU region means the message will be sent through https://api.eu.sendgrid.com :param region: :return: """ if region in region_host_dict.keys(): self.host = region_host_dict[region] - self.client = python_http_client.Client( - host=self.host, - request_headers=self._default_headers, - version=3) + if self._default_headers is not None: + self.client = python_http_client.Client( + host=self.host, + request_headers=self._default_headers, + version=3) else: raise ValueError("region can only be \"eu\" or \"global\"") diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 7e53a5e1e..608bd3521 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -33,7 +33,7 @@ def __init__( self, api_key=None, host='https://api.sendgrid.com', - region='global', + region=None, impersonate_subuser=None): """ Construct the Twilio SendGrid v3 API object. diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py index 1815d43a5..72b88ba67 100644 --- a/test/unit/test_sendgrid.py +++ b/test/unit/test_sendgrid.py @@ -40,4 +40,8 @@ def test_with_region_is_none(self): def test_with_region_is_invalid(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_data_residency("abc") \ No newline at end of file + sg.set_data_residency("abc") + + def test_host_with_both_host_and_region_in_constructor(self): + sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host="https://example.com",region="eu") + self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) \ No newline at end of file From da3f03c5641fd32d82dfe477788e4d484f38b3aa Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Mon, 20 Nov 2023 15:01:41 +0530 Subject: [PATCH 15/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- sendgrid/base_interface.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 86ed18cab..b95847d53 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -3,7 +3,7 @@ region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} class BaseInterface(object): - def __init__(self, auth, host, impersonate_subuser, region='global'): + def __init__(self, auth, host, impersonate_subuser, region=None): """ Construct the Twilio SendGrid v3 API object. Note that the underlying client is being set up during initialization, From f86747b1d688178f509b14809e4363d7bc0e3269 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 22 Nov 2023 14:01:25 +0530 Subject: [PATCH 16/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- sendgrid/base_interface.py | 18 +++--------------- sendgrid/sendgrid.py | 3 +-- test/unit/test_sendgrid.py | 22 +--------------------- 3 files changed, 5 insertions(+), 38 deletions(-) diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index b95847d53..0288cdfe6 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -3,7 +3,7 @@ region_host_dict = {'eu':'https://api.eu.sendgrid.com','global':'https://api.sendgrid.com'} class BaseInterface(object): - def __init__(self, auth, host, impersonate_subuser, region=None): + def __init__(self, auth, host, impersonate_subuser): """ Construct the Twilio SendGrid v3 API object. Note that the underlying client is being set up during initialization, @@ -20,18 +20,13 @@ def __init__(self, auth, host, impersonate_subuser, region=None): :type impersonate_subuser: string :param host: base URL for API calls :type host: string - :param region: To determine the region which can only be 'global' or 'eu' - :type region: string """ from . import __version__ self.auth = auth self.impersonate_subuser = impersonate_subuser self.version = __version__ self.useragent = 'sendgrid/{};python'.format(self.version) - if region is None: - self.host = host - else: - self.set_data_residency(region=region) + self.host = host self.client = python_http_client.Client( host=self.host, @@ -67,13 +62,6 @@ def send(self, message): return self.client.mail.send.post(request_body=message) - def set_host(self, host): - self.host = host - self.client = python_http_client.Client( - host=self.host, - request_headers=self._default_headers, - version=3) - def set_data_residency(self, region): """ Client libraries contain setters for specifying region/edge. @@ -81,7 +69,7 @@ def set_data_residency(self, region): Global is the default residency (or region) Global region means the message will be sent through https://api.sendgrid.com EU region means the message will be sent through https://api.eu.sendgrid.com - :param region: + :param region: string :return: """ if region in region_host_dict.keys(): diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index 608bd3521..d8d0610d7 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -33,7 +33,6 @@ def __init__( self, api_key=None, host='https://api.sendgrid.com', - region=None, impersonate_subuser=None): """ Construct the Twilio SendGrid v3 API object. @@ -58,5 +57,5 @@ def __init__( self.api_key = api_key or os.environ.get('SENDGRID_API_KEY') auth = 'Bearer {}'.format(self.api_key) - super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser,region) + super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser) diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py index 72b88ba67..ef5db13e3 100644 --- a/test/unit/test_sendgrid.py +++ b/test/unit/test_sendgrid.py @@ -16,22 +16,6 @@ def test_host_with_global_region(self): sg.set_data_residency("global") self.assertEqual("https://api.sendgrid.com",sg.client.host) - def test_host_with_host_first_eu_region_second(self): - sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_host("https://sendgrid.com") - sg.set_data_residency("eu") - self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) - - def test_host_with_eu_first_host_second(self): - sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_data_residency("eu") - sg.set_host("https://sendgrid.com") - self.assertEqual("https://sendgrid.com",sg.client.host) - - def test_host_using_constructor(self): - sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host='https://sendgrid.com') - self.assertEqual("https://sendgrid.com",sg.client.host) - def test_with_region_is_none(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): @@ -40,8 +24,4 @@ def test_with_region_is_none(self): def test_with_region_is_invalid(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_data_residency("abc") - - def test_host_with_both_host_and_region_in_constructor(self): - sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY',host="https://example.com",region="eu") - self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) \ No newline at end of file + sg.set_data_residency("abc") \ No newline at end of file From 0a958777727a3e5b1d41c52c93da75cc87c18484 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 22 Nov 2023 14:09:01 +0530 Subject: [PATCH 17/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 23 +++-------------------- sendgrid/base_interface.py | 2 +- 2 files changed, 4 insertions(+), 21 deletions(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index aa3d6aa9b..9a36248aa 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -7,40 +7,23 @@ # setting region to be "global" sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg.set_data_residency("global") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" content = Content("text/plain", "and easy to do anywhere, even with Python") print(sg.client.host) mail = Mail(from_email, to_email, subject, content) +sg.set_sendgrid_data_residency("global") response = sg.client.mail.send.post(request_body=mail.get()) print(response) print(response.status_code) print(response.body) print(response.headers) - # Example 2 -# setting host -sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg.set_host("https://api.eu.sendgrid.com") -from_email = Email("example@abc.com") -to_email = To("example@abc.com") -subject = "Sending with SendGrid is Fun" -content = Content("text/plain", "and easy to do anywhere, even with Python") -print(sg.client.host) -mail = Mail(from_email, to_email, subject, content) -response = sg.client.mail.send.post(request_body=mail.get()) -print(response) -print(response.status_code) -print(response.body) -print(response.headers) - -# Example 3 # setting region to "eu" -sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY')) -sg.set_data_residency("eu") +sg = sendgrid.SendGridAPIClient(api_key=os.environ.get('SENDGRID_API_KEY_EU')) +sg.set_sendgrid_data_residency("eu") from_email = Email("example@abc.com") to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" diff --git a/sendgrid/base_interface.py b/sendgrid/base_interface.py index 0288cdfe6..f94f09479 100644 --- a/sendgrid/base_interface.py +++ b/sendgrid/base_interface.py @@ -62,7 +62,7 @@ def send(self, message): return self.client.mail.send.post(request_body=message) - def set_data_residency(self, region): + def set_sendgrid_data_residency(self, region): """ Client libraries contain setters for specifying region/edge. This supports global and eu regions only. This set will likely expand in the future. From 41312f454982c52d9cc60c2c789704789bd3e95a Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 22 Nov 2023 14:09:36 +0530 Subject: [PATCH 18/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- sendgrid/sendgrid.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index d8d0610d7..e09ed1948 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -51,8 +51,6 @@ def __init__( :type impersonate_subuser: string :param host: base URL for API calls :type host: string - :param region: To determine the region which can only be 'global' or 'eu' - :type region: string """ self.api_key = api_key or os.environ.get('SENDGRID_API_KEY') auth = 'Bearer {}'.format(self.api_key) From 9f73f25e7f753e750ff1f73539eb28990311a392 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 22 Nov 2023 14:09:58 +0530 Subject: [PATCH 19/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- sendgrid/sendgrid.py | 1 - 1 file changed, 1 deletion(-) diff --git a/sendgrid/sendgrid.py b/sendgrid/sendgrid.py index e09ed1948..912d8336e 100644 --- a/sendgrid/sendgrid.py +++ b/sendgrid/sendgrid.py @@ -56,4 +56,3 @@ def __init__( auth = 'Bearer {}'.format(self.api_key) super(SendGridAPIClient, self).__init__(auth, host, impersonate_subuser) - From 7eb07f72b5dd38b4ce010a7b573becfa5cff22e2 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Wed, 22 Nov 2023 14:15:50 +0530 Subject: [PATCH 20/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- test/unit/test_sendgrid.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/unit/test_sendgrid.py b/test/unit/test_sendgrid.py index ef5db13e3..328d978ab 100644 --- a/test/unit/test_sendgrid.py +++ b/test/unit/test_sendgrid.py @@ -8,20 +8,20 @@ def test_host_with_no_region(self): def test_host_with_eu_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_data_residency("eu") + sg.set_sendgrid_data_residency("eu") self.assertEqual("https://api.eu.sendgrid.com",sg.client.host) def test_host_with_global_region(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') - sg.set_data_residency("global") + sg.set_sendgrid_data_residency("global") self.assertEqual("https://api.sendgrid.com",sg.client.host) def test_with_region_is_none(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_data_residency(None) + sg.set_sendgrid_data_residency(None) def test_with_region_is_invalid(self): sg = sendgrid.SendGridAPIClient(api_key='MY_API_KEY') with self.assertRaises(ValueError): - sg.set_data_residency("abc") \ No newline at end of file + sg.set_sendgrid_data_residency("abc") \ No newline at end of file From d760424ac80ac06d39448318c7d9b249e09e0132 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 23 Nov 2023 14:55:00 +0530 Subject: [PATCH 21/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- examples/dataresidency/set_region.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/dataresidency/set_region.py b/examples/dataresidency/set_region.py index 9a36248aa..9aae2611f 100644 --- a/examples/dataresidency/set_region.py +++ b/examples/dataresidency/set_region.py @@ -11,9 +11,9 @@ to_email = To("example@abc.com") subject = "Sending with SendGrid is Fun" content = Content("text/plain", "and easy to do anywhere, even with Python") -print(sg.client.host) mail = Mail(from_email, to_email, subject, content) sg.set_sendgrid_data_residency("global") +print(sg.client.host) response = sg.client.mail.send.post(request_body=mail.get()) print(response) print(response.status_code) From 7fc733d049536ef438f218ba07074ea3b0fe8c27 Mon Sep 17 00:00:00 2001 From: manisha1997 Date: Thu, 23 Nov 2023 16:23:54 +0530 Subject: [PATCH 22/22] feat: geolocation setter in sendgrid-python for GDPR compliance --- .github/workflows/lint-python.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lint-python.yml b/.github/workflows/lint-python.yml index 1c5f53f23..ace47f77d 100644 --- a/.github/workflows/lint-python.yml +++ b/.github/workflows/lint-python.yml @@ -13,4 +13,4 @@ jobs: steps: - uses: actions/checkout@v3 - run: pip install --user ruff - - run: ruff --format=github --ignore="E722,F40,F841" --line-length=681 --target-version=py37 . + - run: ruff --ignore="E722,F40,F841" --line-length=320 --target-version=py37 .