-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
UID2-3497: Support for /identity/buckets #46
Merged
Merged
Changes from all commits
Commits
Show all changes
10 commits
Select commit
Hold shift + click to select a range
24ab854
Support for /identity/buckets
caroline-ttd 4ab20bb
Handling empyty bucket list in sample usage
caroline-ttd 890557a
Address the comments
caroline-ttd 9cfdbb8
Address the comments
caroline-ttd 87044ac
Remove unused import
caroline-ttd 100ec8a
Address the comments
caroline-ttd db5548d
Merge branch 'main' into ccm-UID2-3497-implement-identity-buckets
caroline-ttd c5f235d
Address the comments
caroline-ttd 01b844b
Move the unit tests to a new file
caroline-ttd 260fd8c
Polish IdentityMapUnitTests
caroline-ttd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import sys | ||
from datetime import datetime | ||
|
||
from uid2_client import IdentityMapClient | ||
|
||
|
||
# this sample client takes timestamp string as input and generates an IdentityBucketsResponse object which contains | ||
# a list of buckets, the timestamp string in the format YYYY-MM-DD[*HH[:MM[:SS[.fff[fff]]]][+HH:MM[:SS[.ffffff]]]], | ||
# for example: UTC: 2024-07-02, 2024-07-02T14:30:15.123456+00:00 and EST: 2024-07-02T14:30:15.123456-05:00 | ||
|
||
def _usage(): | ||
print('Usage: python3 sample_get_identity_buckets.py <base_url> <api_key> <client_secret> <timestamp>' | ||
, file=sys.stderr) | ||
sys.exit(1) | ||
|
||
|
||
if len(sys.argv) <= 4: | ||
_usage() | ||
|
||
base_url = sys.argv[1] | ||
api_key = sys.argv[2] | ||
client_secret = sys.argv[3] | ||
timestamp = sys.argv[4] | ||
|
||
client = IdentityMapClient(base_url, api_key, client_secret) | ||
|
||
identity_buckets_response = client.get_identity_buckets(datetime.fromisoformat(timestamp)) | ||
|
||
if identity_buckets_response.buckets: | ||
for bucket in identity_buckets_response.buckets: | ||
print("The bucket id of the bucket: ", bucket.get_bucket_id()) | ||
print("The last updated timestamp of the bucket: ", bucket.get_last_updated()) | ||
else: | ||
print("No bucket was returned") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
import datetime as dt | ||
import os | ||
import unittest | ||
|
||
from urllib.error import URLError, HTTPError | ||
|
||
from uid2_client import IdentityMapClient, IdentityMapInput, normalize_and_hash_email, normalize_and_hash_phone | ||
|
@@ -130,24 +132,29 @@ def test_identity_map_hashed_phones(self): | |
|
||
self.assert_unmapped(response, "optout", hashed_opted_out_phone) | ||
|
||
def test_identity_map_bad_url(self): | ||
def test_identity_map_client_bad_url(self): | ||
identity_map_input = IdentityMapInput.from_emails( | ||
["[email protected]", "[email protected]", "[email protected]"]) | ||
client = IdentityMapClient("https://operator-bad-url.uidapi.com", os.getenv("UID2_API_KEY"), os.getenv("UID2_SECRET_KEY")) | ||
self.assertRaises(URLError, client.generate_identity_map, identity_map_input) | ||
self.assertRaises(URLError, client.get_identity_buckets, dt.datetime.now()) | ||
|
||
def test_identity_map_bad_api_key(self): | ||
def test_identity_map_client_bad_api_key(self): | ||
identity_map_input = IdentityMapInput.from_emails( | ||
["[email protected]", "[email protected]", "[email protected]"]) | ||
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), "bad-api-key", os.getenv("UID2_SECRET_KEY")) | ||
self.assertRaises(HTTPError, client.generate_identity_map,identity_map_input) | ||
self.assertRaises(HTTPError, client.get_identity_buckets, dt.datetime.now()) | ||
|
||
def test_identity_map_bad_secret(self): | ||
def test_identity_map_client_bad_secret(self): | ||
identity_map_input = IdentityMapInput.from_emails( | ||
["[email protected]", "[email protected]", "[email protected]"]) | ||
|
||
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), os.getenv("UID2_API_KEY"), "wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=") | ||
self.assertRaises(HTTPError, client.generate_identity_map, | ||
identity_map_input) | ||
self.assertRaises(HTTPError, client.get_identity_buckets, | ||
dt.datetime.now()) | ||
|
||
def assert_mapped(self, response, dii): | ||
mapped_identity = response.mapped_identities.get(dii) | ||
|
@@ -165,6 +172,15 @@ def assert_unmapped(self, response, reason, dii): | |
mapped_identity = response.mapped_identities.get(dii) | ||
self.assertIsNone(mapped_identity) | ||
|
||
def test_identity_buckets(self): | ||
response = self.identity_map_client.get_identity_buckets(dt.datetime.now() - dt.timedelta(days=90)) | ||
self.assertTrue(len(response.buckets) > 0) | ||
self.assertTrue(response.is_success) | ||
|
||
def test_identity_buckets_empty_response(self): | ||
response = self.identity_map_client.get_identity_buckets(dt.datetime.now() + dt.timedelta(days=1)) | ||
self.assertTrue(len(response.buckets) == 0) | ||
self.assertTrue(response.is_success) | ||
|
||
if __name__ == '__main__': | ||
unittest.main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import unittest | ||
import datetime as dt | ||
|
||
from uid2_client import IdentityMapClient, get_datetime_utc_iso_format | ||
|
||
|
||
class IdentityMapUnitTests(unittest.TestCase): | ||
identity_map_client = IdentityMapClient("UID2_BASE_URL", "UID2_API_KEY", "wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=") | ||
|
||
def test_identity_buckets_invalid_timestamp(self): | ||
test_cases = ["1234567890", | ||
1234567890, | ||
2024.7, | ||
"2024-7-1", | ||
"2024-07-01T12:00:00", | ||
[2024, 7, 1, 12, 0, 0], | ||
None] | ||
for timestamp in test_cases: | ||
self.assertRaises(AttributeError, self.identity_map_client.get_identity_buckets, | ||
timestamp) | ||
|
||
def test_get_datetime_utc_iso_format_timestamp(self): | ||
expected_timestamp = "2024-07-02T14:30:15.123456" | ||
test_cases = ["2024-07-02T14:30:15.123456+00:00", "2024-07-02 09:30:15.123456-05:00", | ||
"2024-07-02T08:30:15.123456-06:00", "2024-07-02T10:30:15.123456-04:00", | ||
"2024-07-02T06:30:15.123456-08:00", "2024-07-02T23:30:15.123456+09:00", | ||
"2024-07-03T00:30:15.123456+10:00", "2024-07-02T20:00:15.123456+05:30"] | ||
for timestamp_str in test_cases: | ||
timestamp = dt.datetime.fromisoformat(timestamp_str) | ||
iso_format_timestamp = get_datetime_utc_iso_format(timestamp) | ||
self.assertEqual(expected_timestamp, iso_format_timestamp) | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import json | ||
|
||
|
||
class IdentityBucketsResponse: | ||
def __init__(self, response): | ||
self._buckets = [] | ||
response_json = json.loads(response) | ||
self._status = response_json["status"] | ||
|
||
if not self.is_success(): | ||
raise ValueError("Got unexpected identity buckets status: " + self._status) | ||
|
||
body = response_json["body"] | ||
|
||
for bucket in body: | ||
self._buckets.append(Bucket.from_json(bucket)) | ||
|
||
def is_success(self): | ||
return self._status == "success" | ||
|
||
@property | ||
def buckets(self): | ||
return self._buckets | ||
|
||
@property | ||
def status(self): | ||
return self._status | ||
|
||
|
||
class Bucket: | ||
def __init__(self, bucket_id, last_updated): | ||
self._bucket_id = bucket_id | ||
self._last_updated = last_updated | ||
|
||
def get_bucket_id(self): | ||
return self._bucket_id | ||
|
||
def get_last_updated(self): | ||
return self._last_updated | ||
|
||
@staticmethod | ||
def from_json(json_obj): | ||
return Bucket( | ||
json_obj.get("bucket_id"), | ||
json_obj.get("last_updated") | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked how Python's @patch and call_args work together. Creating a single simple method might be easier for this unit tests.