diff --git a/python/examples/integrations/writers/Writing_Reference_Profiles_to_WhyLabs.ipynb b/python/examples/integrations/writers/Writing_Reference_Profiles_to_WhyLabs.ipynb index 57714da50c..506179eeec 100644 --- a/python/examples/integrations/writers/Writing_Reference_Profiles_to_WhyLabs.ipynb +++ b/python/examples/integrations/writers/Writing_Reference_Profiles_to_WhyLabs.ipynb @@ -59,38 +59,12 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": null, "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Requirement already satisfied: whylogs in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (1.3.1)\n", - "Requirement already satisfied: platformdirs<4.0.0,>=3.5.0 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (3.10.0)\n", - "Requirement already satisfied: protobuf>=3.19.4 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (4.24.2)\n", - "Requirement already satisfied: requests<3.0,>=2.27 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (2.31.0)\n", - "Requirement already satisfied: types-requests<3.0.0.0,>=2.30.0.0 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (2.31.0.2)\n", - "Requirement already satisfied: typing-extensions>=3.10 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (4.7.1)\n", - "Requirement already satisfied: whylabs-client<0.6.0,>=0.5.5 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (0.5.5)\n", - "Requirement already satisfied: whylogs-sketching>=3.4.1.dev3 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylogs) (3.4.1.dev3)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from requests<3.0,>=2.27->whylogs) (3.2.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from requests<3.0,>=2.27->whylogs) (3.4)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from requests<3.0,>=2.27->whylogs) (1.26.16)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from requests<3.0,>=2.27->whylogs) (2023.7.22)\n", - "Requirement already satisfied: types-urllib3 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from types-requests<3.0.0.0,>=2.30.0.0->whylogs) (1.26.25.14)\n", - "Requirement already satisfied: python-dateutil in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from whylabs-client<0.6.0,>=0.5.5->whylogs) (2.8.2)\n", - "Requirement already satisfied: six>=1.5 in /home/anthony/workspace/whylogs/python/.venv/lib/python3.9/site-packages (from python-dateutil->whylabs-client<0.6.0,>=0.5.5->whylogs) (1.16.0)\n", - "\u001b[33mDEPRECATION: feast 0.22.4 has a non-standard dependency specifier googleapis-common-protos<2,>=1.52.*. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of feast or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mDEPRECATION: feast 0.22.4 has a non-standard dependency specifier PyYAML<7,>=5.4.*. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of feast or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", - "\u001b[0m\u001b[33mDEPRECATION: feast 0.22.4 has a non-standard dependency specifier dask<2022.02.0,>=2021.*. pip 23.3 will enforce this behaviour change. A possible replacement is to upgrade to a newer version of feast or contact the author to suggest that they release a version with a conforming dependency specifiers. Discussion can be found at https://github.com/pypa/pip/issues/12063\u001b[0m\u001b[33m\n", - "\u001b[0mNote: you may need to restart the kernel to use updated packages.\n" - ] - } - ], + "outputs": [], "source": [ "# Note: you may need to restart the kernel to use updated packages.\n", - "%pip install whylogs" + "%pip install whylogs==1.3.32" ] }, { @@ -350,7 +324,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "![alt text](images/whylabs.png)\n" + "![alt text](images/reference_profile.png)\n" ] }, { diff --git a/python/examples/integrations/writers/images/reference_profile.png b/python/examples/integrations/writers/images/reference_profile.png new file mode 100644 index 0000000000..3dd81ef4b9 Binary files /dev/null and b/python/examples/integrations/writers/images/reference_profile.png differ diff --git a/python/tests/api/writer/test_whylabs_integration.py b/python/tests/api/writer/test_whylabs_integration.py index 602c4d08ff..72d80c6325 100644 --- a/python/tests/api/writer/test_whylabs_integration.py +++ b/python/tests/api/writer/test_whylabs_integration.py @@ -314,6 +314,52 @@ def test_post_log_unsegmented_reference_retry(): assert exc_info.value.status == 429 +@pytest.mark.load +def test_log_reference(): + ORG_ID = _get_org() + MODEL_ID = os.environ.get("WHYLABS_DEFAULT_DATASET_ID") + why.init(reinit=True, allow_local=False) + data = {"col1": 1, "col2": "foo"} + trace_id = str(uuid4()) + why.log(data, trace_id=trace_id, name="foo") + time.sleep(SLEEP_TIME) # platform needs time to become aware of the profile + writer = WhyLabsWriter() + dataset_api = DatasetProfileApi(writer._api_client) + response: ProfileTracesResponse = dataset_api.get_profile_traces( + org_id=ORG_ID, + dataset_id=MODEL_ID, + trace_id=trace_id, + ) + download_url = response.get("traces")[0]["download_url"] + headers = {"Content-Type": "application/octet-stream"} + downloaded_profile = writer._s3_pool.request("GET", download_url, headers=headers, timeout=writer._timeout_seconds) + deserialized_view = DatasetProfileView.deserialize(downloaded_profile.data) + assert deserialized_view.get_columns().keys() == data.keys() + + +@pytest.mark.load +def test_log_batch(): + ORG_ID = _get_org() + MODEL_ID = os.environ.get("WHYLABS_DEFAULT_DATASET_ID") + why.init(reinit=True, allow_local=False) + data = {"col1": 1, "col2": "foo"} + trace_id = str(uuid4()) + why.log(data, trace_id=trace_id) + time.sleep(SLEEP_TIME) # platform needs time to become aware of the profile + writer = WhyLabsWriter() + dataset_api = DatasetProfileApi(writer._api_client) + response: ProfileTracesResponse = dataset_api.get_profile_traces( + org_id=ORG_ID, + dataset_id=MODEL_ID, + trace_id=trace_id, + ) + download_url = response.get("traces")[0]["download_url"] + headers = {"Content-Type": "application/octet-stream"} + downloaded_profile = writer._s3_pool.request("GET", download_url, headers=headers, timeout=writer._timeout_seconds) + deserialized_view = DatasetProfileView.deserialize(downloaded_profile.data) + assert deserialized_view.get_columns().keys() == data.keys() + + @pytest.mark.load def test_whylabs_writer(): ORG_ID = _get_org() diff --git a/python/whylogs/api/whylabs/session/session.py b/python/whylogs/api/whylabs/session/session.py index 08656431bf..9d985f0d28 100644 --- a/python/whylogs/api/whylabs/session/session.py +++ b/python/whylogs/api/whylabs/session/session.py @@ -279,8 +279,10 @@ def __create_log_api(self, config: SessionConfig) -> LogApi: def upload_reference_profiles(self, profile_aliases: Dict[str, ResultSet]) -> Union[UploadResult, NotSupported]: results: List[str] = [] for alias, profile in profile_aliases.items(): - result = profile.writer("whylabs").option(reference_profile_name=alias).write() - results.append(*[id for status, id in result if status]) + success, ids = profile.writer("whylabs").option(reference_profile_name=alias).write() + if success: + ids = ids if isinstance(ids, list) else [(True, ids)] + results.append(*[id for _, id in ids]) request: GetProfileObservatoryLinkRequest = GetProfileObservatoryLinkRequest( reference_profile_ids=results, batch_profile_timestamps=[]