Repository: snowplow/snowplow-python-tracker

Issue:
Update payload builder to combine event subjects
Currently only one event subject is added to the payload, these should be combined to prevent loss of information in line with other SS trackers.

Discussion:
coveralls: 
[![Coverage Status](https://coveralls.io/builds/60708615/badge)](https://coveralls.io/builds/60708615)

coverage: 95.943% (+1.3%) from 94.604% when pulling **55e6dd15b2abc4f3d0b2002bfa071a0f707a6404 on issue/347-combine_event_subjects** into **033c7802be90467daa9588bc8d2b76a03cb9e01d on master**.


Patch:
diff --git a/examples/tracker_api_example/app.py b/examples/tracker_api_example/app.py
index 3777a59..41f520c 100644
--- a/examples/tracker_api_example/app.py
+++ b/examples/tracker_api_example/app.py
@@ -31,10 +31,13 @@ def main():
 
     print("Sending events to " + e.endpoint)
 
+    event_subject = Subject()
+    event_subject.set_color_depth(10)
+
     page_view = PageView(
         page_url="https://www.snowplow.io",
         page_title="Homepage",
-        event_subject=t.subject,
+        event_subject=event_subject,
     )
     t.track(page_view)
 
diff --git a/snowplow_tracker/events/event.py b/snowplow_tracker/events/event.py
index 7f510ba..c9d9b82 100644
--- a/snowplow_tracker/events/event.py
+++ b/snowplow_tracker/events/event.py
@@ -94,10 +94,13 @@ class Event(object):
         ):
             self.payload.add("ttm", int(self.true_timestamp))
 
-        fin_subject = self.event_subject if self.event_subject is not None else subject
+        if self.event_subject is not None:
+            fin_payload_dict = self.event_subject.combine_subject(subject)
+        else:
+            fin_payload_dict = None if subject is None else subject.standard_nv_pairs
 
-        if fin_subject is not None:
-            self.payload.add_dict(fin_subject.standard_nv_pairs)
+        if fin_payload_dict is not None:
+            self.payload.add_dict(fin_payload_dict)
         return self.payload
 
     @property
diff --git a/snowplow_tracker/subject.py b/snowplow_tracker/subject.py
index 10bcbe2..c3165d3 100644
--- a/snowplow_tracker/subject.py
+++ b/snowplow_tracker/subject.py
@@ -15,8 +15,9 @@
 #     language governing permissions and limitations there under.
 # """
 
+from typing import Optional
 from snowplow_tracker.contracts import one_of, greater_than
-from snowplow_tracker.typing import SupportedPlatform, SUPPORTED_PLATFORMS
+from snowplow_tracker.typing import SupportedPlatform, SUPPORTED_PLATFORMS, PayloadDict
 
 DEFAULT_PLATFORM = "pc"
 
@@ -29,7 +30,6 @@ class Subject(object):
     """
 
     def __init__(self) -> None:
-
         self.standard_nv_pairs = {"p": DEFAULT_PLATFORM}
 
     def set_platform(self, value: SupportedPlatform) -> "Subject":
@@ -173,3 +173,16 @@ class Subject(object):
         """
         self.standard_nv_pairs["tnuid"] = nuid
         return self
+
+    def combine_subject(self, subject: Optional["Subject"]) -> PayloadDict:
+        """
+        Merges another instance of Subject, with self taking priority
+        :param  subject     Subject to update
+        :type   subject     subject
+        :rtype              PayloadDict
+
+        """
+        if subject is not None:
+            return {**subject.standard_nv_pairs, **self.standard_nv_pairs}
+
+        return self.standard_nv_pairs


Test patch:
diff --git a/snowplow_tracker/test/unit/test_subject.py b/snowplow_tracker/test/unit/test_subject.py
index 7645781..953a0a7 100644
--- a/snowplow_tracker/test/unit/test_subject.py
+++ b/snowplow_tracker/test/unit/test_subject.py
@@ -86,3 +86,31 @@ class TestSubject(unittest.TestCase):
             s.standard_nv_pairs["vid"]
         with pytest.raises(KeyError):
             s.standard_nv_pairs["tnuid"]
+
+    def test_combine_subject(self) -> None:
+        s = _subject.Subject()
+        s.set_color_depth(10)
+        s.set_domain_session_id("domain_session_id")
+
+        s2 = _subject.Subject()
+        s2.set_domain_user_id("domain_user_id")
+        s2.set_lang("en")
+
+        fin_payload_dict = s.combine_subject(s2)
+
+        expected_fin_payload_dict = {
+            "p": "pc",
+            "cd": 10,
+            "sid": "domain_session_id",
+            "duid": "domain_user_id",
+            "lang": "en",
+        }
+
+        expected_subject = {
+            "p": "pc",
+            "cd": 10,
+            "sid": "domain_session_id",
+        }
+
+        self.assertDictEqual(fin_payload_dict, expected_fin_payload_dict)
+        self.assertDictEqual(s.standard_nv_pairs, expected_subject)