This is an automated email from the ASF dual-hosted git repository.

fokko pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git


The following commit(s) were added to refs/heads/main by this push:
     new 7b84d108 Clean up logging: move exception tracebacks to debug level 
(#2867)
7b84d108 is described below

commit 7b84d10826e6f231991e2e9bb6f944b21dc98632
Author: Kevin Liu <[email protected]>
AuthorDate: Tue Jan 6 03:49:57 2026 -0500

    Clean up logging: move exception tracebacks to debug level (#2867)
    
    <!--
    Thanks for opening a pull request!
    -->
    
    <!-- In the case this PR will resolve an issue, please replace
    ${GITHUB_ISSUE_ID} below with the actual Github issue id. -->
    <!-- Closes #${GITHUB_ISSUE_ID} -->
    
    # Rationale for this change
    I noticed we dump the entire error traceback in log warn messages. This
    causes a wall of text when using the CLI.
    
    This PR conditionally dump traceback only for `debug` log level. This
    provides cleaner user-facing output by default while still making
    detailed exception info available for troubleshooting via debug logging.
    - Users now see clean one-line warnings instead of full tracebacks.
    - Developers can enable debug logging to see detailed exception info.
    
    Using the shorthand, `exc_info` in logging.warning's kwargs:
    
    
https://docs.python.org/3/library/logging.html#:~:text=If%20exc_info%20does%20not%20evaluate%20as%20false%2C%20it%20causes%20exception%20information%20to%20be%20added%20to%20the%20logging%20message.%20If%20an%20exception%20tuple%20(in%20the%20format%20returned%20by%20sys.exc_info())%20or%20an%20exception%20instance%20is%20provided%2C%20it%20is%20used%3B%20otherwise%2C%20sys.exc_info()%20is%20called%20to%20get%20the%20exception%20information.
    
    
    ## Are these changes tested?
    
    ## Are there any user-facing changes?
    
    <!-- In the case of user-facing changes, please add the changelog label.
    -->
    
    #### Before
    ```
    Could not initialize FileIO: pyiceberg.io.pyarrow.PyArrowFileIO
    Traceback (most recent call last):
      File "/Users/kevinliu/repos/iceberg-python/pyiceberg/io/__init__.py", 
line 321, in _import_file_io
        module = importlib.import_module(module_name)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File 
"/Users/kevinliu/.pyenv/versions/3.12.11/lib/python3.12/importlib/__init__.py", 
line 90, in import_module
        return _bootstrap._gcd_import(name[level:], package, level)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
      File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
      File "<frozen importlib._bootstrap>", line 1331, in 
_find_and_load_unlocked
      File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
      File "<frozen importlib._bootstrap_external>", line 999, in exec_module
      File "<frozen importlib._bootstrap>", line 488, in 
_call_with_frames_removed
      File "/Users/kevinliu/repos/iceberg-python/pyiceberg/io/pyarrow.py", line 
54, in <module>
        import pyarrow as pa
    ModuleNotFoundError: No module named 'pyarrow'
    ```
    #### After
    ```
    Could not initialize FileIO: pyiceberg.io.pyarrow.PyArrowFileIO
    ```
---
 pyiceberg/catalog/__init__.py | 12 ++++++------
 pyiceberg/io/__init__.py      |  4 ++--
 pyiceberg/table/locations.py  |  7 +++++--
 tests/io/test_io.py           |  4 ++++
 tests/table/test_locations.py |  4 ++++
 5 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/pyiceberg/catalog/__init__.py b/pyiceberg/catalog/__init__.py
index a4f1d47b..d1d83c6d 100644
--- a/pyiceberg/catalog/__init__.py
+++ b/pyiceberg/catalog/__init__.py
@@ -285,8 +285,8 @@ def delete_files(io: FileIO, files_to_delete: set[str], 
file_type: str) -> None:
     for file in files_to_delete:
         try:
             io.delete(file)
-        except OSError as exc:
-            logger.warning(msg=f"Failed to delete {file_type} file {file}", 
exc_info=exc)
+        except OSError:
+            logger.warning(f"Failed to delete {file_type} file {file}", 
exc_info=logger.isEnabledFor(logging.DEBUG))
 
 
 def delete_data_files(io: FileIO, manifests_to_delete: list[ManifestFile]) -> 
None:
@@ -305,8 +305,8 @@ def delete_data_files(io: FileIO, manifests_to_delete: 
list[ManifestFile]) -> No
             if not deleted_files.get(path, False):
                 try:
                     io.delete(path)
-                except OSError as exc:
-                    logger.warning(msg=f"Failed to delete data file {path}", 
exc_info=exc)
+                except OSError:
+                    logger.warning(f"Failed to delete data file {path}", 
exc_info=logger.isEnabledFor(logging.DEBUG))
                 deleted_files[path] = True
 
 
@@ -319,8 +319,8 @@ def _import_catalog(name: str, catalog_impl: str, 
properties: Properties) -> Cat
         module = importlib.import_module(module_name)
         class_ = getattr(module, class_name)
         return class_(name, **properties)
-    except ModuleNotFoundError as exc:
-        logger.warning(f"Could not initialize Catalog: {catalog_impl}", 
exc_info=exc)
+    except ModuleNotFoundError:
+        logger.warning(f"Could not initialize Catalog: {catalog_impl}", 
exc_info=logger.isEnabledFor(logging.DEBUG))
         return None
 
 
diff --git a/pyiceberg/io/__init__.py b/pyiceberg/io/__init__.py
index c7109993..87d155a0 100644
--- a/pyiceberg/io/__init__.py
+++ b/pyiceberg/io/__init__.py
@@ -321,8 +321,8 @@ def _import_file_io(io_impl: str, properties: Properties) 
-> FileIO | None:
         module = importlib.import_module(module_name)
         class_ = getattr(module, class_name)
         return class_(properties)
-    except ModuleNotFoundError as exc:
-        logger.warning(f"Could not initialize FileIO: {io_impl}", exc_info=exc)
+    except ModuleNotFoundError:
+        logger.warning(f"Could not initialize FileIO: {io_impl}", 
exc_info=logger.isEnabledFor(logging.DEBUG))
         return None
 
 
diff --git a/pyiceberg/table/locations.py b/pyiceberg/table/locations.py
index 25da7e7f..3aeaaf22 100644
--- a/pyiceberg/table/locations.py
+++ b/pyiceberg/table/locations.py
@@ -178,8 +178,11 @@ def _import_location_provider(
         module = importlib.import_module(module_name)
         class_ = getattr(module, class_name)
         return class_(table_location, table_properties)
-    except ModuleNotFoundError as exc:
-        logger.warning(f"Could not initialize LocationProvider: 
{location_provider_impl}", exc_info=exc)
+    except ModuleNotFoundError:
+        logger.warning(
+            f"Could not initialize LocationProvider: {location_provider_impl}",
+            exc_info=logger.isEnabledFor(logging.DEBUG),
+        )
         return None
 
 
diff --git a/tests/io/test_io.py b/tests/io/test_io.py
index ac1d7b4f..d9bee33f 100644
--- a/tests/io/test_io.py
+++ b/tests/io/test_io.py
@@ -279,7 +279,11 @@ def test_import_file_io() -> None:
 
 
 def test_import_file_io_does_not_exist(caplog: Any) -> None:
+    import logging
+
+    caplog.set_level(logging.DEBUG)
     assert _import_file_io("pyiceberg.does.not.exist.FileIO", {}) is None
+    assert "Could not initialize FileIO: pyiceberg.does.not.exist.FileIO" in 
caplog.text
     assert "ModuleNotFoundError: No module named 'pyiceberg.does'" in 
caplog.text
 
 
diff --git a/tests/table/test_locations.py b/tests/table/test_locations.py
index 3634151d..6dd7520f 100644
--- a/tests/table/test_locations.py
+++ b/tests/table/test_locations.py
@@ -66,10 +66,14 @@ def test_custom_location_provider_single_path() -> None:
 
 
 def test_custom_location_provider_not_found(caplog: Any) -> None:
+    import logging
+
+    caplog.set_level(logging.DEBUG)
     with pytest.raises(ValueError, match=r"Could not initialize 
LocationProvider"):
         load_location_provider(
             table_location="table_location", 
table_properties={"write.py-location-provider.impl": "module.not_found"}
         )
+    assert "Could not initialize LocationProvider: module.not_found" in 
caplog.text
     assert "ModuleNotFoundError: No module named 'module'" in caplog.text
 
 

Reply via email to