Skip to content

Commit

Permalink
FIX: Coverge Test 3
Browse files Browse the repository at this point in the history
  • Loading branch information
syedhamidali committed Sep 4, 2024
1 parent 1e136ac commit 2de6ac7
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 42 deletions.
71 changes: 51 additions & 20 deletions tests/io/test_auto_read.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import logging
import signal
from unittest.mock import MagicMock, patch

Expand All @@ -10,6 +11,8 @@
# Mocked functions for testing
def mock_open_success(file):
mock_dtree = MagicMock(name="DataTree")
# Mock the behavior of georeference to return the same object without changing attrs
mock_dtree.xradar.georeference.return_value = mock_dtree
return mock_dtree


Expand Down Expand Up @@ -82,8 +85,8 @@ def test_read_nonlocal_dtree(sample_file):


# Test for georeferencing and verbose output
def test_read_with_georeferencing_and_verbose(sample_file, capsys):
# Test successful reading with georeferencing and verbose mode.
def test_read_with_georeferencing_and_logging(sample_file, caplog):
# Test successful reading with georeferencing and log output.
with (
patch("xradar.io.auto_read.io.__all__", ["open_nexradlevel2_datatree"]),
patch(
Expand All @@ -92,36 +95,39 @@ def test_read_with_georeferencing_and_verbose(sample_file, capsys):
),
patch("xarray.core.dataset.Dataset.pipe", side_effect=mock_georeference),
):
dtree = auto_read.read(sample_file, georeference=True, verbose=True)
assert dtree is not None
with caplog.at_level(logging.DEBUG):
dtree = auto_read.read(sample_file, georeference=True, verbose=True)
assert dtree is not None

# Capture the printed output
captured = capsys.readouterr()
assert "Georeferencing radar data..." in captured.out
assert (
"File opened successfully using open_nexradlevel2_datatree." in captured.out
)
# Check that the log messages contain the correct information
assert "Georeferencing radar data..." in caplog.text
assert (
"File opened successfully using open_nexradlevel2_datatree."
in caplog.text
)


# Test for exception handling and verbose output during failure
def test_read_failure_with_verbose_output(sample_file, capsys):
# Test that it handles exceptions and prints the verbose failure message.
def test_read_failure_with_verbose_output(sample_file, caplog):
# Test that it handles exceptions and logs the verbose failure message.
with (
patch("xradar.io.auto_read.io.__all__", ["open_nexradlevel2_datatree"]),
patch(
"xradar.io.auto_read.io.open_nexradlevel2_datatree",
side_effect=mock_open_failure,
),
):
with pytest.raises(
ValueError,
match="File could not be opened by any supported format in xradar.io.",
):
auto_read.read(sample_file, georeference=True, verbose=True)
with caplog.at_level(logging.DEBUG):
with pytest.raises(
ValueError,
match="File could not be opened by any supported format in xradar.io.",
):
auto_read.read(sample_file, georeference=True, verbose=True)

# Capture the printed output
captured = capsys.readouterr()
assert "Failed to open with open_nexradlevel2_datatree" in captured.out
# Check that the failure log messages contain the correct information
assert (
"Failed to open with open_nexradlevel2_datatree" in caplog.text
) # Capturing log instead of print


# Test for raising ValueError when no format can open the file
Expand Down Expand Up @@ -195,3 +201,28 @@ def test_read_with_timeout(sample_file):
auto_read.TimeoutException, match="Radar file reading timed out."
):
auto_read.read(sample_file, timeout=1)


def test_read_comment_update(sample_file):
with (
patch("xradar.io.auto_read.io.__all__", ["open_nexradlevel2_datatree"]),
patch(
"xradar.io.auto_read.io.open_nexradlevel2_datatree",
side_effect=mock_open_success,
),
):
dtree = auto_read.read(sample_file)
assert dtree is not None

# Print the actual value of the 'comment' attribute for debugging
print(f"Actual comment: {dtree.attrs['comment']}")

# The initial comment is "im/exported using xradar" (lowercase 'i')
expected_comment_start = "im/exported using xradar"

# Ensure the comment starts with the correct initial value
assert dtree.attrs["comment"].startswith(expected_comment_start)

# Ensure the comment has the correct format with 'nexradlevel2'
expected_comment_end = ",\n'nexradlevel2'"
assert dtree.attrs["comment"].endswith(expected_comment_end)
131 changes: 109 additions & 22 deletions xradar/io/auto_read.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,15 @@
XRadar Auto Reader
==================
This module provides the ability to automatically read radar files using all
available formats in the `xradar.io` module. It supports handling various file
types, georeferencing, and logging, as well as a timeout mechanism for file reading.
.. autosummary::
:nosignatures:
:toctree: generated/
{}
read
"""

__all__ = [
Expand All @@ -19,22 +23,69 @@

__doc__ = __doc__.format("\n ".join(__all__))

from .. import io # noqa
import logging
import signal

from .. import io # noqa

# Setup a logger for this module
logger = logging.getLogger(__name__)
logging.basicConfig(
level=logging.WARNING
) # Default log level to suppress debug logs unless verbose is set


# Custom exception for handling timeouts
class TimeoutException(Exception):
"""
Custom exception to handle file read timeouts.
This exception is raised when the radar file reading process exceeds the
specified timeout duration.
"""

pass


# Timeout handler
def timeout_handler(signum, frame):
"""
Timeout handler to raise a TimeoutException.
This function is triggered by the alarm signal when the radar file reading
exceeds the allowed timeout duration.
Parameters
----------
signum : int
The signal number (in this case, SIGALRM).
frame : frame object
The current stack frame at the point where the signal was received.
Raises
------
TimeoutException
If the reading operation takes too long and exceeds the timeout.
"""
raise TimeoutException("Radar file reading timed out.")


# Decorator for handling timeouts
def with_timeout(timeout):
"""
Decorator to enforce a timeout on the file reading process.
This decorator wraps the file reading function to ensure that if it takes longer than the
specified `timeout` duration, it raises a `TimeoutException`.
Parameters
----------
timeout : int
The maximum number of seconds allowed for the file reading process.
Returns
-------
function
A wrapped function that raises `TimeoutException` if it exceeds the timeout.
"""

def decorator(func):
def wrapper(*args, **kwargs):
# Set the signal handler and a timeout
Expand All @@ -56,8 +107,9 @@ def read(file, georeference=True, verbose=False, timeout=None):
Attempt to read a radar file using all available formats in xradar.io.
This function iterates over all the available file-opening functions in the
xradar.io module and attempts to open the provided radar file. If successful,
it can optionally georeference the data (adding x, y, z coordinates).
`xradar.io` module and attempts to open the provided radar file. If successful,
it can optionally georeference the data (adding x, y, z coordinates) and log
detailed processing information.
Parameters
----------
Expand All @@ -66,19 +118,20 @@ def read(file, georeference=True, verbose=False, timeout=None):
georeference : bool, optional
If True, georeference the radar data by adding x, y, z coordinates (default is True).
verbose : bool, optional
If True, prints out detailed processing information (default is False).
If True, prints out detailed processing information (default is False). When set to True,
debug-level logs are enabled. When False, only warnings and errors are logged.
timeout : int or None, optional
Timeout in seconds for reading the radar file. If None, no timeout is applied (default is None).
Returns
-------
dtree : DataTree
A DataTree object containing the radar data.
A `DataTree` object containing the radar data.
Raises
------
ValueError
If the file could not be opened by any supported format in xradar.io.
If the file could not be opened by any supported format in `xradar.io`.
TimeoutException
If reading the file takes longer than the specified timeout.
Expand All @@ -93,7 +146,18 @@ def read(file, georeference=True, verbose=False, timeout=None):
-----
This function relies on the `xradar` library to support various radar file formats.
It tries to open the file using all available `open_` functions in the `xradar.io` module.
If a `comment` attribute exists in the radar file's metadata, this function appends the
radar type to the comment. The default comment is set to "im/exported using xradar".
"""
# Configure logger level based on 'verbose'
if verbose:
logger.setLevel(logging.DEBUG) # Enable debug messages when verbose is True
logger.debug("Verbose mode activated.")
else:
logger.setLevel(
logging.WARNING
) # Suppress debug messages when verbose is False

dtree = None

# Wrap the read process with a timeout if specified
Expand All @@ -107,16 +171,30 @@ def attempt_read(file):
open_func = getattr(io, key)
try:
dtree = open_func(file)

# Ensure the 'comment' key exists; if not, create it
if "comment" not in dtree.attrs:
logger.debug("Creating new 'comment' key.")
dtree.attrs["comment"] = "im/exported using xradar"
else:
logger.debug(

Check warning on line 180 in xradar/io/auto_read.py

View check run for this annotation

Codecov / codecov/patch

xradar/io/auto_read.py#L180

Added line #L180 was not covered by tests
f"Existing 'comment': {dtree.attrs['comment']}"
)

# Append the key information to the comment without quotes
dtree.attrs["comment"] += f",\n{key.split('_')[1]}"

# Log the updated comment
logger.debug(f"After update: {dtree.attrs['comment']}")

if georeference:
if verbose:
print("Georeferencing radar data...")
logger.debug("Georeferencing radar data...")
dtree = dtree.xradar.georeference()
if verbose:
print(f"File opened successfully using {key}.")

logger.debug(f"File opened successfully using {key}.")
break
except Exception as e:
if verbose:
print(f"Failed to open with {key}: {e}")
logger.debug(f"Failed to open with {key}: {e}")
continue

Check warning on line 198 in xradar/io/auto_read.py

View check run for this annotation

Codecov / codecov/patch

xradar/io/auto_read.py#L196-L198

Added lines #L196 - L198 were not covered by tests

if dtree is None:
Expand All @@ -133,16 +211,25 @@ def attempt_read(file):
open_func = getattr(io, key)
try:
dtree = open_func(file)

if "comment" not in dtree.attrs:
logger.debug("Creating new 'comment' key.")
dtree.attrs["comment"] = "im/exported using xradar"
else:
logger.debug(

Check warning on line 219 in xradar/io/auto_read.py

View check run for this annotation

Codecov / codecov/patch

xradar/io/auto_read.py#L219

Added line #L219 was not covered by tests
f"Existing 'comment' before update: {dtree.attrs['comment']}"
)

dtree.attrs["comment"] += f",\n{key.split('_')[1]}"

if georeference:
if verbose:
print("Georeferencing radar data...")
logger.debug("Georeferencing radar data...")
dtree = dtree.xradar.georeference()
if verbose:
print(f"File opened successfully using {key}.")

logger.debug(f"File opened successfully using {key}.")
break
except Exception as e:
if verbose:
print(f"Failed to open with {key}: {e}")
logger.debug(f"Failed to open with {key}: {e}")
continue

if dtree is None:
Expand Down

0 comments on commit 2de6ac7

Please sign in to comment.