Skip to content

Commit 47b76c9

Browse files
committed
Reapply "Replace urllib with requests" (#47)
This reverts commit 7f3a72b. # Conflicts: # pyproject.toml # tests/test_identity_map_client.py # uid2_client/request_response_util.py
1 parent 8481edd commit 47b76c9

File tree

9 files changed

+65
-51
lines changed

9 files changed

+65
-51
lines changed

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ classifiers = [
1818
"License :: OSI Approved :: MIT License",
1919
"Operating System :: OS Independent",
2020
]
21-
requires-python = ">=3.6"
21+
requires-python = ">=3.8"
2222
dependencies = [
23-
"setuptools",
23+
"requests",
2424
"pycryptodome",
2525
"bitarray"
2626
]

tests/test_identity_map_client.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33
import unittest
44

5-
from urllib.error import URLError, HTTPError
5+
import requests
66

77
from uid2_client import IdentityMapClient, IdentityMapInput, normalize_and_hash_email, normalize_and_hash_phone
88

@@ -142,22 +142,20 @@ def test_identity_map_client_bad_url(self):
142142
identity_map_input = IdentityMapInput.from_emails(
143143
144144
client = IdentityMapClient("https://operator-bad-url.uidapi.com", os.getenv("UID2_API_KEY"), os.getenv("UID2_SECRET_KEY"))
145-
self.assertRaises(URLError, client.generate_identity_map, identity_map_input)
146-
self.assertRaises(URLError, client.get_identity_buckets, dt.datetime.now())
145+
self.assertRaises(requests.exceptions.ConnectionError, client.generate_identity_map, identity_map_input)
147146

148147
def test_identity_map_client_bad_api_key(self):
149148
identity_map_input = IdentityMapInput.from_emails(
150149
151150
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), "bad-api-key", os.getenv("UID2_SECRET_KEY"))
152-
self.assertRaises(HTTPError, client.generate_identity_map,identity_map_input)
153-
self.assertRaises(HTTPError, client.get_identity_buckets, dt.datetime.now())
151+
self.assertRaises(requests.exceptions.HTTPError, client.generate_identity_map,identity_map_input)
154152

155153
def test_identity_map_client_bad_secret(self):
156154
identity_map_input = IdentityMapInput.from_emails(
157155
158156

159157
client = IdentityMapClient(os.getenv("UID2_BASE_URL"), os.getenv("UID2_API_KEY"), "wJ0hP19QU4hmpB64Y3fV2dAed8t/mupw3sjN5jNRFzg=")
160-
self.assertRaises(HTTPError, client.generate_identity_map,
158+
self.assertRaises(requests.exceptions.HTTPError, client.generate_identity_map,
161159
identity_map_input)
162160
self.assertRaises(HTTPError, client.get_identity_buckets,
163161
dt.datetime.now())

tests/test_publisher_client.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
import os
22
import unittest
33

4+
import requests
5+
46
from uid2_client import Uid2PublisherClient
57
from uid2_client import TokenGenerateInput
6-
from uid2_client import TokenGenerateResponse
78
from uid2_client.identity_tokens import IdentityTokens
8-
from urllib.request import HTTPError
99

1010

1111
@unittest.skipIf(
@@ -187,7 +187,7 @@ def test_integration_bad_requests(self):
187187

188188
expired_respose = "{\"advertising_token\":\"AgAAAAN6QZRCFTau+sfOlMMUY2ftElFMq2TCrcu1EAaD9WmEfoT2BWm2ZKz1tumbT00tWLffRDQ/9POXfA0O/Ljszn7FLtG5EzTBM3HYs4f5irkqeEvu38DhVCxUEpI+gZZZkynRap1oYx6AmC/ip3rk+7pmqa3r3saDs1mPRSSTm+Nh6A==\",\"user_token\":\"AgAAAAL6aleYI4BubI5ZXMBshqmMEfCkbCJF4fLeg1sdI0BTLzj9sXsSISjkG0lMC743diC2NVy3ElkbO1lLysd+Lm6alkqevPrcuWDisQ1939YdoH6LqpwBH3FNSE4/xa3Q+94=\",\"refresh_token\":\"AAAAAARomrP3NjjH+8mt5djfTHbmRZXjOMnAN8WpjJoe30AhUCvYksO/xoDSj77GzWv4M99DhnPl2cVco8CZFTcE10nauXI4Barr890ILnH0IIacOei5Zjwh6DycFkoXkAAuHY1zjmxb7niGLfSP2RctWkZdRVGWQv/UW/grw6+paU9bnKEWPzVvLwwdW2NgjDKu+szE6A+b5hkY+I3voKoaz8/kLDmX8ddJGLy/YOh/LIveBspSAvEg+v89OuUCwAqm8L3Rt8PxDzDnt0U4Na+AUawvvfsIhmsn/zMpRRks6GHhIAB/EQUHID8TedU8Hv1WFRsiraG9Dfn1Kc5/uYnDJhEagWc+7RgTGT+U5GqI6+afrAl5091eBLbmvXnXn9ts\",\"identity_expires\":1668059799628,\"refresh_expires\":1668142599628,\"refresh_from\":1668056202628,\"refresh_response_key\":\"P941vVeuyjaDRVnFQ8DPd0AZnW4bPeiJPXER2K9QXcU=\"}"
189189
current_identity = IdentityTokens.from_json_string(expired_respose)
190-
with self.assertRaises(HTTPError):
190+
with self.assertRaises(requests.exceptions.HTTPError):
191191
self.publisher_client.refresh_token(current_identity)
192192

193193
with self.assertRaises(TypeError):
@@ -197,15 +197,15 @@ def test_integration_bad_requests(self):
197197
self.publisher_client.refresh_token(None)
198198

199199
bad_url_client = Uid2PublisherClient("https://www.something.com", self.UID2_API_KEY, self.UID2_SECRET_KEY)
200-
with self.assertRaises(HTTPError):
200+
with self.assertRaises(requests.exceptions.HTTPError):
201201
bad_url_client.generate_token(TokenGenerateInput.from_email("[email protected]"))
202202

203203
bad_secret_client = Uid2PublisherClient(self.UID2_BASE_URL, self.UID2_API_KEY, "badSecretKeypB64Y3fV2dAed8t/mupw3sjN5jNRFzg=")
204-
with self.assertRaises(HTTPError):
204+
with self.assertRaises(requests.exceptions.HTTPError):
205205
bad_secret_client.generate_token(TokenGenerateInput.from_email("[email protected]"))
206206

207207
bad_api_client = Uid2PublisherClient(self.UID2_BASE_URL, "not-real-key", self.UID2_SECRET_KEY)
208-
with self.assertRaises(HTTPError):
208+
with self.assertRaises(requests.exceptions.HTTPError):
209209
bad_secret_client.generate_token(TokenGenerateInput.from_email("[email protected]"))
210210

211211

tests/test_refresh_keys_util.py

Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,14 @@
11
import json
22
import unittest
3-
from unittest.mock import patch
3+
4+
import responses
45

56
from uid2_client import refresh_keys_util
67
from test_utils import *
78
from uid2_client.encryption import _encrypt_gcm, _decrypt_gcm
89

910

1011
class TestRefreshKeysUtil(unittest.TestCase):
11-
class MockPostResponse:
12-
def __init__(self, return_value):
13-
self.return_value = return_value
14-
15-
def read(self):
16-
return base64.b64encode(self.return_value)
17-
1812
def _make_post_response(self, request_data, response_payload):
1913
d = base64.b64decode(request_data)[1:]
2014
d = _decrypt_gcm(d, client_secret_bytes)
@@ -25,11 +19,11 @@ def _make_post_response(self, request_data, response_payload):
2519
payload += response_payload
2620
envelope = _encrypt_gcm(payload, None, client_secret_bytes)
2721

28-
return self.MockPostResponse(envelope)
22+
return 200, {}, base64.b64encode(envelope)
2923

30-
def _get_post_refresh_keys_response(self, base_url, path, headers, data):
24+
def _get_post_refresh_keys_response(self, request):
3125
response_payload = key_set_to_json_for_sharing([master_key, site_key]).encode()
32-
return self._make_post_response(data, response_payload)
26+
return self._make_post_response(request.body, response_payload)
3327

3428
def _validate_master_and_site_key(self, keys):
3529
self.assertEqual(len(keys.values()), 2)
@@ -55,23 +49,29 @@ def _validate_master_and_site_key(self, keys):
5549
self.assertEqual(master_secret, master.secret)
5650
self.assertEqual(1, master.keyset_id)
5751

58-
@patch('uid2_client.refresh_keys_util.post')
59-
def test_refresh_sharing_keys(self, mock_post):
60-
mock_post.side_effect = self._get_post_refresh_keys_response
61-
refresh_response = refresh_keys_util.refresh_sharing_keys("base_url", "auth_key", base64.b64decode(client_secret))
52+
@responses.activate
53+
def test_refresh_sharing_keys(self):
54+
responses.add_callback(
55+
responses.POST,
56+
"https://base_url/v2/key/sharing",
57+
callback=self._get_post_refresh_keys_response,
58+
)
59+
60+
refresh_response = refresh_keys_util.refresh_sharing_keys("https://base_url", "auth_key", base64.b64decode(client_secret))
6261
self.assertTrue(refresh_response.success)
6362
self._validate_master_and_site_key(refresh_response.keys)
64-
mock_post.assert_called_once()
65-
self.assertEqual(mock_post.call_args[0], ('base_url', '/v2/key/sharing'))
6663

67-
@patch('uid2_client.refresh_keys_util.post')
68-
def test_refresh_bidstream_keys(self, mock_post):
69-
mock_post.side_effect = self._get_post_refresh_keys_response
70-
refresh_response = refresh_keys_util.refresh_bidstream_keys("base_url", "auth_key", base64.b64decode(client_secret))
64+
@responses.activate
65+
def test_refresh_bidstream_keys(self):
66+
responses.add_callback(
67+
responses.POST,
68+
"https://base_url/v2/key/bidstream",
69+
callback=self._get_post_refresh_keys_response,
70+
)
71+
72+
refresh_response = refresh_keys_util.refresh_bidstream_keys("https://base_url", "auth_key", base64.b64decode(client_secret))
7173
self.assertTrue(refresh_response.success)
7274
self._validate_master_and_site_key(refresh_response.keys)
73-
mock_post.assert_called_once()
74-
self.assertEqual(mock_post.call_args[0], ('base_url', '/v2/key/bidstream'))
7575

7676
def test_parse_keys_json_identity(self):
7777
response_body_str = key_set_to_json_for_sharing([master_key, site_key])

uid2_client/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
decrypt_token: decrypt and advertising token to extract advertising ID from it
88
"""
99

10+
default_new_session = lambda: None
1011

1112
from .auto_refresh import *
1213
from .client import *

uid2_client/identity_map_client.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def generate_identity_map(self, identity_map_input):
3838
req, nonce = make_v2_request(self._client_secret, dt.datetime.now(tz=timezone.utc),
3939
identity_map_input.get_identity_map_input_as_json_string().encode())
4040
resp = post(self._base_url, '/v2/identity/map', headers=auth_headers(self._api_key), data=req)
41-
resp_body = parse_v2_response(self._client_secret, resp.read(), nonce)
41+
resp.raise_for_status()
42+
resp_body = parse_v2_response(self._client_secret, resp.text, nonce)
4243
return IdentityMapResponse(resp_body, identity_map_input)
4344

4445
def get_identity_buckets(self, since_timestamp):

uid2_client/publisher_client.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,14 @@ def generate_token(self, token_generate_input):
5050
req, nonce = make_v2_request(self._secret_key, dt.datetime.now(tz=timezone.utc),
5151
token_generate_input.get_as_json_string().encode())
5252
resp = post(self._base_url, '/v2/token/generate', headers=auth_headers(self._auth_key), data=req)
53-
resp_body = parse_v2_response(self._secret_key, resp.read(), nonce)
53+
resp.raise_for_status()
54+
resp_body = parse_v2_response(self._secret_key, resp.text, nonce)
5455
return TokenGenerateResponse(resp_body)
5556

5657
def refresh_token(self, current_identity):
5758
resp = post(self._base_url, '/v2/token/refresh', headers=auth_headers(self._auth_key),
5859
data=current_identity.get_refresh_token().encode())
59-
resp_bytes = base64_to_byte_array(resp.read())
60+
resp.raise_for_status()
61+
resp_bytes = base64_to_byte_array(resp.text)
6062
decrypted = _decrypt_gcm(resp_bytes, base64_to_byte_array(current_identity.get_refresh_response_key()))
6163
return TokenRefreshResponse(decrypted.decode(), dt.datetime.now(tz=timezone.utc))

uid2_client/refresh_keys_util.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ def _fetch_keys(base_url, path, auth_key, secret_key):
3838
try:
3939
req, nonce = make_v2_request(secret_key, dt.datetime.now(tz=timezone.utc))
4040
resp = post(base_url, path, headers=auth_headers(auth_key), data=req)
41-
resp_body = json.loads(parse_v2_response(secret_key, resp.read(), nonce)).get('body')
41+
resp.raise_for_status()
42+
resp_body = json.loads(parse_v2_response(secret_key, resp.text, nonce)).get('body')
4243
keys = _parse_keys_json(resp_body)
4344
return RefreshResponse.make_success(keys)
4445
except Exception as exc:

uid2_client/request_response_util.py

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import base64
2+
import importlib.metadata
23
import os
3-
from urllib import request
4+
import threading
5+
from typing import Optional
6+
import requests
47

5-
import pkg_resources
6-
7-
from uid2_client.encryption import _encrypt_gcm, _decrypt_gcm
8+
import uid2_client
9+
from uid2_client.encryption import _decrypt_gcm, _encrypt_gcm
810

911

1012
def _make_url(base_url, path):
@@ -13,12 +15,12 @@ def _make_url(base_url, path):
1315

1416
def auth_headers(auth_key):
1517
try:
16-
version = pkg_resources.get_distribution("uid2_client").version
18+
client_version = importlib.metadata.version("uid2_client")
1719
except Exception:
18-
version = "non-packaged-mode"
20+
client_version = "non-packaged-mode"
1921

2022
return {'Authorization': 'Bearer ' + auth_key,
21-
"X-UID2-Client-Version": "uid2-client-python-" + version}
23+
"X-UID2-Client-Version": "uid2-client-python-" + client_version}
2224

2325

2426
def make_v2_request(secret_key, now, data=None):
@@ -41,6 +43,15 @@ def parse_v2_response(secret_key, encrypted, nonce):
4143
return payload[16:]
4244

4345

44-
def post(base_url, path, headers, data):
45-
req = request.Request(_make_url(base_url, path), headers=headers, method='POST', data=data)
46-
return request.urlopen(req)
46+
def __default_new_session(threadlocal=threading.local()):
47+
if getattr(threadlocal, 'session', None) is None:
48+
threadlocal.session = requests.Session()
49+
50+
return threadlocal.session
51+
52+
53+
def post(base_url, path, headers, data, session: Optional[requests.Session] = None):
54+
session = (session or uid2_client.default_new_session()
55+
) or __default_new_session()
56+
57+
return session.post(_make_url(base_url, path), data=data, headers=headers, timeout=5)

0 commit comments

Comments
 (0)