Repository: ASFHyP3/hyp3-sdk

Issue:
Add custom User Agent header to hyp3 api session
e.g. `User-Agent: hyp3-sdk v0.1.2` so we can identify SDK-generated requests in the API access logs, separate from other requests made via `requests`.

Discussion:

Patch:
diff --git a/hyp3_sdk/hyp3.py b/hyp3_sdk/hyp3.py
index 7d90095..baf69f4 100644
--- a/hyp3_sdk/hyp3.py
+++ b/hyp3_sdk/hyp3.py
@@ -6,6 +6,7 @@ from urllib.parse import urljoin
 
 from requests.exceptions import HTTPError, RequestException
 
+import hyp3_sdk
 from hyp3_sdk.exceptions import HyP3Error, ValidationError
 from hyp3_sdk.jobs import Batch, Job
 from hyp3_sdk.util import get_authenticated_session
@@ -28,6 +29,7 @@ class HyP3:
         """
         self.url = api_url
         self.session = get_authenticated_session(username, password)
+        self.session.headers.update({'User-Agent': f'{hyp3_sdk.__name__}/{hyp3_sdk.__version__}'})
 
     def find_jobs(self, start: Optional[datetime] = None, end: Optional[datetime] = None,
                   status: Optional[str] = None, name: Optional[str] = None) -> Batch:


Test patch:
diff --git a/tests/test_hyp3.py b/tests/test_hyp3.py
index 626ee05..9aa05e9 100644
--- a/tests/test_hyp3.py
+++ b/tests/test_hyp3.py
@@ -1,4 +1,3 @@
-import json
 from datetime import datetime, timedelta
 from urllib.parse import urljoin
 
@@ -10,6 +9,18 @@ from hyp3_sdk import HyP3, Job
 hyp3_sdk.TESTING = True
 
 
+@responses.activate
+def test_session_headers():
+    api = HyP3()
+    responses.add(responses.GET, urljoin(api.url, '/user'), json={'foo': 'bar'})
+
+    api.session.get(urljoin(api.url, '/user'))
+    assert responses.calls[0].request.headers['User-Agent'] == f'hyp3_sdk/{hyp3_sdk.__version__}'
+
+    api.my_info()
+    assert responses.calls[1].request.headers['User-Agent'] == f'hyp3_sdk/{hyp3_sdk.__version__}'
+
+
 @responses.activate
 def test_find_jobs(get_mock_job):
     api_response_mock = {
@@ -23,7 +34,7 @@ def test_find_jobs(get_mock_job):
         ]
     }
     api = HyP3()
-    responses.add(responses.GET, urljoin(api.url, '/jobs'), body=json.dumps(api_response_mock))
+    responses.add(responses.GET, urljoin(api.url, '/jobs'), json=api_response_mock)
     response = api.find_jobs()
     assert len(response) == 3
 
@@ -32,7 +43,7 @@ def test_find_jobs(get_mock_job):
 def test_get_job_by_id(get_mock_job):
     job = get_mock_job()
     api = HyP3()
-    responses.add(responses.GET, urljoin(api.url, f'/jobs/{job.job_id}'), body=json.dumps(job.to_dict()))
+    responses.add(responses.GET, urljoin(api.url, f'/jobs/{job.job_id}'), json=job.to_dict())
     response = api._get_job_by_id(job.job_id)
     assert response == job
 
@@ -45,9 +56,9 @@ def test_watch(get_mock_job):
     api = HyP3()
     for ii in range(3):
         responses.add(responses.GET, urljoin(api.url, f'/jobs/{incomplete_job.job_id}'),
-                      body=json.dumps(incomplete_job.to_dict()))
+                      json=incomplete_job.to_dict())
     responses.add(responses.GET, urljoin(api.url, f'/jobs/{incomplete_job.job_id}'),
-                  body=json.dumps(complete_job.to_dict()))
+                  json=complete_job.to_dict())
     response = api.watch(incomplete_job, interval=0.05)
     assert response == complete_job
     responses.assert_call_count(urljoin(api.url, f'/jobs/{incomplete_job.job_id}'), 4)
@@ -60,7 +71,7 @@ def test_refresh(get_mock_job):
     new_job.status_code = 'SUCCEEDED'
 
     api = HyP3()
-    responses.add(responses.GET, urljoin(api.url, f'/jobs/{job.job_id}'), body=json.dumps(new_job.to_dict()))
+    responses.add(responses.GET, urljoin(api.url, f'/jobs/{job.job_id}'), json=new_job.to_dict())
     response = api.refresh(job)
     assert response == new_job
 
@@ -74,7 +85,7 @@ def test_submit_job_dict(get_mock_job):
         ]
     }
     api = HyP3()
-    responses.add(responses.POST, urljoin(api.url, '/jobs'), body=json.dumps(api_response))
+    responses.add(responses.POST, urljoin(api.url, '/jobs'), json=api_response)
     response = api.submit_job_dict(job.to_dict(for_resubmit=True))
     assert response == job
 
@@ -88,7 +99,7 @@ def test_submit_autorift_job(get_mock_job):
         ]
     }
     api = HyP3()
-    responses.add(responses.POST, urljoin(api.url, '/jobs'), body=json.dumps(api_response))
+    responses.add(responses.POST, urljoin(api.url, '/jobs'), json=api_response)
     response = api.submit_autorift_job('g1', 'g2')
     assert response == job
 
@@ -102,7 +113,7 @@ def test_submit_rtc_job(get_mock_job):
         ]
     }
     api = HyP3()
-    responses.add(responses.POST, urljoin(api.url, '/jobs'), body=json.dumps(api_response))
+    responses.add(responses.POST, urljoin(api.url, '/jobs'), json=api_response)
     response = api.submit_rtc_job('g1')
     assert response == job
 
@@ -116,7 +127,7 @@ def test_submit_insar_job(get_mock_job):
         ]
     }
     api = HyP3()
-    responses.add(responses.POST, urljoin(api.url, '/jobs'), body=json.dumps(api_response))
+    responses.add(responses.POST, urljoin(api.url, '/jobs'), json=api_response)
     response = api.submit_insar_job('g1', 'g2')
     assert response == job
 
@@ -135,7 +146,7 @@ def test_my_info():
         'user_id': 'someUser'
     }
     api = HyP3()
-    responses.add(responses.GET, urljoin(api.url, '/user'), body=json.dumps(api_response))
+    responses.add(responses.GET, urljoin(api.url, '/user'), json=api_response)
     response = api.my_info()
     assert response == api_response
 
@@ -154,6 +165,6 @@ def test_check_quota():
         'user_id': 'someUser'
     }
     api = HyP3()
-    responses.add(responses.GET, urljoin(api.url, '/user'), body=json.dumps(api_response))
+    responses.add(responses.GET, urljoin(api.url, '/user'), json=api_response)
     response = api.check_quota()
     assert response == api_response['quota']['remaining']