Repository: meltano/sdk (python)

Issue:
[Bug]: Too many `Properties () were present in the '...' stream` messages
### Singer SDK Version

0.13.1

### Python Version

NA

### Bug scope

Taps (catalog, state, stream maps, etc.)

### Operating System

Any

### Description

From @visch in Slack:

> Seeing a lot of
> ```
> time=2022-11-09 20:52:36 name=tap-activedirectory level=INFO message=Properties () were present in the 'users' stream but not found in catalog schema. Ignoring.
> ```
> Lately, anyone else? empty properties() object? Maybe a sdk bug?

Issue is in line https://github.com/meltano/sdk/blob/a3f64db222f9f046fff16910a024680979335790/singer_sdk/helpers/_typing.py#L230

### Code

_No response_

Pull request description:
fix: Do not emit log message if no record properties were ignored
Closes #1173

<!-- readthedocs-preview meltano-sdk start -->
----
:books: Documentation preview :books:: https://meltano-sdk--1174.org.readthedocs.build/en/1174/

<!-- readthedocs-preview meltano-sdk end -->

Patch:
diff --git a/poetry.lock b/poetry.lock
index ff5f40fa..2de424c2 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1449,23 +1449,14 @@ binaryornot = [
     {file = "binaryornot-0.4.4.tar.gz", hash = "sha256:359501dfc9d40632edc9fac890e19542db1a287bbcfa58175b66658392018061"},
 ]
 black = [
-    {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"},
-    {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"},
-    {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"},
-    {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"},
-    {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"},
-    {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"},
     {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"},
     {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"},
-    {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"},
     {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"},
     {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"},
     {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"},
     {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"},
-    {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"},
     {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"},
     {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"},
-    {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"},
     {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"},
     {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"},
     {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"},
@@ -2118,13 +2109,6 @@ pyyaml = [
     {file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
     {file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
     {file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
-    {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
-    {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
-    {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
-    {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
     {file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
     {file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
diff --git a/singer_sdk/helpers/_typing.py b/singer_sdk/helpers/_typing.py
index 853b6229..a7296cec 100644
--- a/singer_sdk/helpers/_typing.py
+++ b/singer_sdk/helpers/_typing.py
@@ -314,5 +314,6 @@ def conform_record_data_types(  # noqa: C901
             rec[property_name] = boolean_representation
         else:
             rec[property_name] = elem
-    _warn_unmapped_properties(stream_name, tuple(unmapped_properties), logger)
+    if unmapped_properties:
+        _warn_unmapped_properties(stream_name, tuple(unmapped_properties), logger)
     return rec


Test patch:
diff --git a/tests/core/test_record_typing.py b/tests/core/test_record_typing.py
index d9cc7beb..870a5399 100644
--- a/tests/core/test_record_typing.py
+++ b/tests/core/test_record_typing.py
@@ -1,8 +1,10 @@
 """Typing tests."""
 
+from __future__ import annotations
+
 import logging
 from datetime import datetime
-from typing import Any, Dict
+from typing import Any
 
 import pendulum
 import pytest
@@ -15,31 +17,60 @@ from singer_sdk.helpers._typing import (
 
 
 @pytest.mark.parametrize(
-    "record,schema,expected_row",
+    "record,schema,expected_row,ignore_props_message",
     [
         (
             {"updatedAt": pendulum.parse("2021-08-25T20:05:28+00:00")},
             {"properties": {"updatedAt": True}},
             {"updatedAt": "2021-08-25T20:05:28+00:00"},
+            None,
         ),
         (
             {"updatedAt": pendulum.parse("2021-08-25T20:05:28Z")},
             {"properties": {"updatedAt": True}},
             {"updatedAt": "2021-08-25T20:05:28+00:00"},
+            None,
         ),
         (
             {"updatedAt": pendulum.parse("2021-08-25T20:05:28")},
             {"properties": {"updatedAt": True}},
             {"updatedAt": "2021-08-25T20:05:28+00:00"},
+            None,
         ),
+        (
+            {"present": 1, "absent": "2"},
+            {"properties": {"present": {"type": "integer"}}},
+            {"present": 1},
+            (
+                "Properties ('absent',) were present in the 'test-stream' stream but "
+                "not found in catalog schema. Ignoring."
+            ),
+        ),
+    ],
+    ids=[
+        "datetime with offset",
+        "datetime with timezone",
+        "datetime without timezone",
+        "ignored_props_message",
     ],
 )
-def test_conform_record_data_types(record: Dict[str, Any], schema: dict, expected_row):
+def test_conform_record_data_types(
+    record: dict[str, Any],
+    schema: dict,
+    expected_row: dict,
+    ignore_props_message: str,
+    caplog: pytest.LogCaptureFixture,
+):
     stream_name = "test-stream"
-    # TODO: mock this out
-    logger = logging.getLogger()
-    actual = conform_record_data_types(stream_name, record, schema, logger)
-    print(record["updatedAt"].isoformat())
+    logger = logging.getLogger("test-logger")
+
+    with caplog.at_level(logging.INFO, logger=logger.name):
+        actual = conform_record_data_types(stream_name, record, schema, logger)
+        if ignore_props_message:
+            assert ignore_props_message in caplog.text
+        else:
+            assert not caplog.text
+
     assert actual == expected_row