From f5d04dc5ba2a6153636ae6276a534698d0cab627 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Mon, 9 Dec 2024 12:13:19 -0700 Subject: [PATCH 01/10] Created a fresh branch to commit changes to files for adding recursive logic, also adjusted current tests to accomdate these changes. I added a new test FDSNFactory_test as well as a mock miniseed client called mseed_FDSN_test_client which is simply the same as mseed_test_client but adapted to use the FDSNSNCL. --- geomagio/api/ws/DataApiQuery.py | 16 +++- geomagio/api/ws/FilterApiQuery.py | 46 ++++++++-- geomagio/api/ws/algorithms.py | 33 ++----- geomagio/api/ws/filter.py | 123 ++++++++++++++++++++++----- test/DataApiQuery_test.py | 6 +- test/FilterApiQuery_test.py | 17 ++-- test/api_test/ws_test/data_test.py | 6 +- test/api_test/ws_test/filter_test.py | 5 +- 8 files changed, 178 insertions(+), 74 deletions(-) diff --git a/geomagio/api/ws/DataApiQuery.py b/geomagio/api/ws/DataApiQuery.py index ac88e609..5e90a33c 100644 --- a/geomagio/api/ws/DataApiQuery.py +++ b/geomagio/api/ws/DataApiQuery.py @@ -1,5 +1,6 @@ import datetime import enum +from enum import Enum import os from typing import List, Optional, Union @@ -40,6 +41,15 @@ class SamplingPeriod(float, enum.Enum): DAY = 86400.0 +class SamplingPeriodWithAuto(str, enum.Enum): + AUTO = "auto" + TEN_HERTZ = SamplingPeriod.TEN_HERTZ.value + SECOND = SamplingPeriod.SECOND.value + MINUTE = SamplingPeriod.MINUTE.value + HOUR = SamplingPeriod.HOUR.value + DAY = SamplingPeriod.DAY.value + + class DataHost(str, enum.Enum): # recognized public Edge data hosts, plus one user-specified DEFAULT = os.getenv("DATA_HOST", "edgecwb.usgs.gov") @@ -69,9 +79,9 @@ class DataApiQuery(BaseModel): endtime: Optional[CustomUTCDateTimeType] = None elements: List[str] = DEFAULT_ELEMENTS sampling_period: SamplingPeriod = SamplingPeriod.MINUTE - data_type: Union[DataType, str] = DataType.VARIATION - format: Union[OutputFormat, str] = OutputFormat.IAGA2002 - data_host: Union[DataHost, str] = DataHost.DEFAULT + data_type: DataType = DataType.VARIATION + format: OutputFormat = OutputFormat.IAGA2002 + data_host: DataHost = DataHost.DEFAULT @field_validator("starttime", mode="before") def validate_starttime( diff --git a/geomagio/api/ws/FilterApiQuery.py b/geomagio/api/ws/FilterApiQuery.py index cb2e4e02..f602fc44 100644 --- a/geomagio/api/ws/FilterApiQuery.py +++ b/geomagio/api/ws/FilterApiQuery.py @@ -1,5 +1,11 @@ -from .DataApiQuery import DataApiQuery, SamplingPeriod, REQUEST_LIMIT -from pydantic import ConfigDict, model_validator +from .DataApiQuery import ( + DataApiQuery, + SamplingPeriod, + REQUEST_LIMIT, + SamplingPeriodWithAuto, +) +from pydantic import ConfigDict, model_validator, field_validator +from typing import Optional, Union """This class inherits all the fields and validation on DataApiQuery and adds the fields input_sampling_period and output_sampling_period.""" @@ -8,16 +14,42 @@ the fields input_sampling_period and output_sampling_period.""" class FilterApiQuery(DataApiQuery): model_config = ConfigDict(extra="forbid") - input_sampling_period: SamplingPeriod = SamplingPeriod.SECOND - output_sampling_period: SamplingPeriod = SamplingPeriod.MINUTE + input_sampling_period: Union[SamplingPeriodWithAuto, float] = ( + SamplingPeriodWithAuto.AUTO + ) + + @field_validator("input_sampling_period", mode="before") + def normalize_sampling_period(cls, value): + if isinstance(value, str) and value == SamplingPeriodWithAuto.AUTO: + return float("nan") # Map 'auto' to NaN internally + if isinstance(value, str): + return float(value) # Map string values to float + try: + value = float(value) # Coerce numeric-like strings to float + except ValueError: + raise ValueError( + f"Invalid sampling period. Must be one of " + f"{[item.value for item in SamplingPeriodWithAuto]}" + ) + # If the value is a float, find its matching enum based on the string value + if isinstance(value, float): + print("The sampling period is touching this logic downstream", type(value)) + # Find matching enum value by checking if the float matches the string equivalent but skip the string "auto" + for period in list(SamplingPeriodWithAuto)[1:]: + if float(period.value) == value: + + return period + + # If no match is found, return the float as-is + return value + + return value # Return the value if it's not a recognized string or float @model_validator(mode="after") def validate_sample_size(self): # Calculate the number of samples based on the input sampling period samples = int( - len(self.elements) - * (self.endtime - self.starttime) - / self.input_sampling_period + len(self.elements) * (self.endtime - self.starttime) / self.sampling_period ) # Validate the request size diff --git a/geomagio/api/ws/algorithms.py b/geomagio/api/ws/algorithms.py index ec18ae9f..879ac70c 100644 --- a/geomagio/api/ws/algorithms.py +++ b/geomagio/api/ws/algorithms.py @@ -15,7 +15,10 @@ from .FilterApiQuery import FilterApiQuery from .data import format_timeseries, get_data_factory, get_data_query, get_timeseries from .filter import get_filter_data_query from . import filter +from ...algorithm.FilterAlgorithm import STEPS +import logging +logger = logging.getLogger(__name__) router = APIRouter() @@ -43,42 +46,16 @@ def get_dbdt( ####################################### The router .get filter isnt visible on the docs page # Look for register routers in the backend - - @router.get( "/algorithms/filter/", description="Filtered data dependent on requested interval", name="Filtered Algorithm", ) -# New query parameter defined below. I am using a new query defined in DataApitQuery. -# This relies on the new filter.py module and the get_filter_data function -# to define input and output sampling period. - - -def get_filter( - query: FilterApiQuery = Depends(get_filter_data_query), -) -> Response: - - filt = FilterAlgorithm( - input_sample_period=query.input_sampling_period, - output_sample_period=query.output_sampling_period, - ) +def get_filter(query: FilterApiQuery = Depends(get_filter_data_query)) -> Response: - # Grab the correct starttime and endtime for the timeseries from get_input_interval - starttime, endtime = filt.get_input_interval(query.starttime, query.endtime) - - # Reassign the actual start/endtime to the query parameters - query.starttime = starttime - query.endtime = endtime - - data_factory = get_data_factory(query=query) - # read data - raw = filter.get_timeseries(data_factory, query) - - filtered_timeseries = filt.process(raw) + filtered_timeseries = filter.get_timeseries(query) elements = [f"{element}" for element in query.elements] - # output response return format_timeseries( timeseries=filtered_timeseries, format=query.format, elements=elements ) diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 54c5f682..234aaa7c 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -1,15 +1,23 @@ from typing import List, Union, Optional from fastapi import Query -from obspy import UTCDateTime, Stream +from obspy.clients.fdsn.header import FDSNNoDataException +from obspy import UTCDateTime, Stream, Trace from ... import TimeseriesFactory, TimeseriesUtility +import math +import numpy as np from .DataApiQuery import ( DEFAULT_ELEMENTS, DataHost, DataType, OutputFormat, SamplingPeriod, + SamplingPeriodWithAuto, ) from .FilterApiQuery import FilterApiQuery +from ...algorithm.FilterAlgorithm import STEPS +from ...algorithm import FilterAlgorithm +import logging as logger +from .data import get_data_factory from ...pydantic_utcdatetime import CustomUTCDateTimeType @@ -26,11 +34,13 @@ def get_filter_data_query( format: Union[OutputFormat, str] = Query( OutputFormat.IAGA2002, title="Output Format" ), - input_sampling_period: Union[SamplingPeriod, float] = Query( - SamplingPeriod.SECOND, title="Initial sampling period" + input_sampling_period: Union[SamplingPeriodWithAuto, float, int] = Query( + SamplingPeriodWithAuto.AUTO, # Assign Default value as auto + title="Initial Sampling Period", + description="Auto will dynamically determine necessary input_sampling_period.", ), - output_sampling_period: Union[SamplingPeriod, float] = Query( - SamplingPeriod.MINUTE, title="Output sampling period" + sampling_period: Union[SamplingPeriod, float] = Query( + SamplingPeriod, alias="output_sampling_period", title="Output sampling period" ), data_host: Union[DataHost, str] = Query( DataHost.DEFAULT, title="Data Host", description="Edge host to pull data from." @@ -43,28 +53,103 @@ def get_filter_data_query( endtime=endtime, elements=elements, input_sampling_period=input_sampling_period, - output_sampling_period=output_sampling_period, + sampling_period=sampling_period, data_type=data_type, data_host=data_host, format=format, ) -def get_timeseries(data_factory: TimeseriesFactory, query: FilterApiQuery) -> Stream: - """Get timeseries data for variometers +# Main filter function +def get_timeseries(query: FilterApiQuery) -> Stream: + data_factory = get_data_factory(query=query) - Parameters - ---------- - data_factory: where to read data - query: parameters for the data to read - """ - # get data - timeseries = data_factory.get_timeseries( - starttime=query.starttime, - endtime=query.endtime, + # Determine input sampling period if not provided + # if query.input_sampling_period == SamplingPeriodWithAuto.AUTO or query.input_sampling_period is None: + if math.isnan(query.input_sampling_period) or query.input_sampling_period is None: + # Dynamically determine the input sampling period + input_sampling_period, data = determine_available_period( + query.sampling_period, query, data_factory + ) + else: + input_sampling_period = query.input_sampling_period + + filt = FilterAlgorithm( + input_sample_period=input_sampling_period, + output_sample_period=query.sampling_period, + ) + # Fetch data + starttime, endtime = filt.get_input_interval(query.starttime, query.endtime) + + data = data_factory.get_timeseries( + starttime=starttime, + endtime=endtime, observatory=query.id, channels=query.elements, type=query.data_type, - interval=TimeseriesUtility.get_interval_from_delta(query.input_sampling_period), + interval=TimeseriesUtility.get_interval_from_delta(filt.input_sample_period), + ) + + # Apply filtering + filtered_timeseries = filt.process(data) + return filtered_timeseries + + +def determine_available_period(output_sampling_period: float, query, data_factory): + """ + Finds the lowest resolution (longest sampling period) <= output_sampling_period + that has valid data available. + """ + + # Sort and filter periods starting from output_sampling_period + sorted_periods: List[SamplingPeriod] = sorted( + SamplingPeriod, key=lambda p: p.value, reverse=True ) - return timeseries + valid_sampling_periods = [ + p for p in sorted_periods if p.value <= output_sampling_period + ] + + for period in valid_sampling_periods: + if period <= output_sampling_period: + + data = data_factory.get_timeseries( + starttime=query.starttime, + endtime=query.endtime, + observatory=query.id, + channels=query.elements, + type=query.data_type, + interval=TimeseriesUtility.get_interval_from_delta(period.value), + ) + # Check if the fetched data is valid + if is_valid_data(data): + + logger.info(f"Valid data found for sampling period: {period.name}") + return period.value, data # Return the sampling period and the data + + else: + logger.error( + f"No valid data found for requested sampling period: {period.name}" + ) + continue + + raise ValueError("No valid data found for the requested output sampling period.") + + +def is_valid_data(data: Stream) -> bool: + """ + Checks if the fetched data contains actual values and not just filler values (e.g., NaN). + A Stream is invalid if any trace contains only NaN values. + """ + if not data or len(data) == 0: + return False # No data in the stream + + for trace in data: + # Check if trace.data exists and has data + if trace.data is None or len(trace.data) == 0: + return False # Trace has no data + + # Check if all values in trace.data are NaN + if np.all(np.isnan(trace.data)): + return False # Invalid if all values are NaN + + return True # All traces are valid diff --git a/test/DataApiQuery_test.py b/test/DataApiQuery_test.py index 117f1758..4434af7d 100644 --- a/test/DataApiQuery_test.py +++ b/test/DataApiQuery_test.py @@ -65,9 +65,9 @@ def test_DataApiQuery_valid(): assert_equal(query.endtime, UTCDateTime("2024-09-01T01:00:01")) assert_equal(query.elements, ["F"]) assert_equal(query.sampling_period, SamplingPeriod.SECOND) - assert_equal(query.data_type, "adjusted") - assert_equal(query.format, "json") - assert_equal(query.data_host, "cwbpub.cr.usgs.gov") + assert_equal(query.data_type, DataType.ADJUSTED) + assert_equal(query.format, OutputFormat.JSON) + assert_equal(query.data_host, DataHost.CWBPUB) def test_DataApiQuery_no_id(): diff --git a/test/FilterApiQuery_test.py b/test/FilterApiQuery_test.py index f4f49a56..1c7c3845 100644 --- a/test/FilterApiQuery_test.py +++ b/test/FilterApiQuery_test.py @@ -5,6 +5,7 @@ from obspy import UTCDateTime from geomagio.api.ws.FilterApiQuery import FilterApiQuery from geomagio.api.ws.DataApiQuery import ( SamplingPeriod, + SamplingPeriodWithAuto, DataType, OutputFormat, DataHost, @@ -22,8 +23,8 @@ def test_FilterApiQuery_defaults(): assert_equal(query.starttime, expected_start_time) assert_equal(query.endtime, expected_endtime) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.input_sampling_period, SamplingPeriod.SECOND) - assert_equal(query.output_sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.input_sampling_period, SamplingPeriodWithAuto.AUTO) + assert_equal(query.sampling_period, SamplingPeriod.MINUTE) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) assert_equal(query.data_host, DataHost.DEFAULT) @@ -36,7 +37,7 @@ def test_FilterApiQuery_valid(): endtime="2024-09-01T01:00:01", elements=["Z"], input_sampling_period=60, - output_sampling_period=3600, + sampling_period=3600, data_type="adjusted", format="json", data_host="cwbpub.cr.usgs.gov", @@ -46,11 +47,11 @@ def test_FilterApiQuery_valid(): assert_equal(query.starttime, UTCDateTime("2024-09-01T00:00:01")) assert_equal(query.endtime, UTCDateTime("2024-09-01T01:00:01")) assert_equal(query.elements, ["Z"]) - assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) - assert_equal(query.output_sampling_period, SamplingPeriod.HOUR) - assert_equal(query.data_type, "adjusted") - assert_equal(query.format, "json") - assert_equal(query.data_host, "cwbpub.cr.usgs.gov") + assert_equal(query.input_sampling_period, SamplingPeriodWithAuto.MINUTE) + assert_equal(query.sampling_period, SamplingPeriod.HOUR) + assert_equal(query.data_type, DataType.ADJUSTED) + assert_equal(query.format, OutputFormat.JSON) + assert_equal(query.data_host, DataHost.CWBPUB) def test_FilterApiQuery_no_id(): diff --git a/test/api_test/ws_test/data_test.py b/test/api_test/ws_test/data_test.py index 3376e311..96fba2f0 100644 --- a/test/api_test/ws_test/data_test.py +++ b/test/api_test/ws_test/data_test.py @@ -28,7 +28,7 @@ def test_client(): def test_get_data_query(test_client): """test.api_test.ws_test.data_test.test_get_data_query()""" response = test_client.get( - "/query/?id=BOU&starttime=2020-09-01T00:00:01&elements=X,Y,Z,F&type=R1&sampling_period=60&format=iaga2002" + "/query/?id=BOU&starttime=2020-09-01T00:00:01&elements=X,Y,Z,F&type=variation&sampling_period=60&format=iaga2002" ) query = DataApiQuery(**response.json()) assert_equal(query.id, "BOU") @@ -36,8 +36,8 @@ def test_get_data_query(test_client): assert_equal(query.endtime, UTCDateTime("2020-09-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) assert_equal(query.sampling_period, SamplingPeriod.MINUTE) - assert_equal(query.format, "iaga2002") - assert_equal(query.data_type, "R1") + assert_equal(query.format, OutputFormat.IAGA2002) + assert_equal(query.data_type, DataType.VARIATION) def test_get_data_query_no_starttime(test_client): diff --git a/test/api_test/ws_test/filter_test.py b/test/api_test/ws_test/filter_test.py index dbd2964e..470e8474 100644 --- a/test/api_test/ws_test/filter_test.py +++ b/test/api_test/ws_test/filter_test.py @@ -31,9 +31,8 @@ def test_get_filter_data_query(test_client): assert_equal(query.starttime, UTCDateTime("2020-09-01T00:00:01")) assert_equal(query.endtime, UTCDateTime("2020-09-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) - assert_equal(query.format, "iaga2002") - assert_equal(query.data_type, "variation") + assert_equal(query.format, OutputFormat.IAGA2002) + assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) assert_equal(query.output_sampling_period, SamplingPeriod.HOUR) -- GitLab From 9236fd2530e501b243f8bd75d2bde9c8554888ea Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Mon, 9 Dec 2024 12:56:45 -0700 Subject: [PATCH 02/10] Forgot to add the two Files in this commit because they weren't being tracked. --- test/edge_test/FDSNFactory_test.py | 206 ++++++++++++++++++++++ test/edge_test/mseed_FDSN_test_clients.py | 47 +++++ 2 files changed, 253 insertions(+) create mode 100644 test/edge_test/FDSNFactory_test.py create mode 100644 test/edge_test/mseed_FDSN_test_clients.py diff --git a/test/edge_test/FDSNFactory_test.py b/test/edge_test/FDSNFactory_test.py new file mode 100644 index 00000000..f409674a --- /dev/null +++ b/test/edge_test/FDSNFactory_test.py @@ -0,0 +1,206 @@ +import io +from typing import List + +import numpy +from numpy.testing import assert_equal, assert_array_equal +import numpy as np +from obspy.core import Stream, Trace, UTCDateTime +from obspy.core.inventory import Inventory, Network, Station, Channel, Site +import pytest + +from geomagio.edge import FDSNFactory +from geomagio.metadata.instrument.InstrumentCalibrations import ( + get_instrument_calibrations, +) +from .mseed_FDSN_test_clients import MockFDSNSeedClient + + +@pytest.fixture(scope="class") +def FDSN_factory() -> FDSNFactory: + """instance of FDSNFactory with MockFDSNClient""" + factory = FDSNFactory() + factory.client = MockFDSNSeedClient() + yield factory + + +@pytest.fixture() +def anmo_u_metadata(): + metadata = get_instrument_calibrations(observatory="ANMO") + instrument = metadata[0]["instrument"] + channels = instrument["channels"] + yield channels["X"] + + +def test__get_timeseries_add_empty_channels(FDSN_factory: FDSNFactory): + """test.edge_test.FDSNFactory_test.test__get_timeseries_add_empty_channels()""" + FDSN_factory.client.return_empty = True + starttime = UTCDateTime("2024-09-07T00:00:00Z") + endtime = UTCDateTime("2024-09-07T00:10:00Z") + trace = FDSN_factory._get_timeseries( + starttime=starttime, + endtime=endtime, + observatory="ANMO", + channel="X", + type="variation", + interval="second", + add_empty_channels=True, + )[0] + + assert_array_equal(trace.data, numpy.ones(trace.stats.npts) * numpy.nan) + assert trace.stats.starttime == starttime + assert trace.stats.endtime == endtime + + with pytest.raises(IndexError): + trace = FDSN_factory._get_timeseries( + starttime=starttime, + endtime=endtime, + observatory="ANMO", + channel="X", + type="variation", + interval="second", + add_empty_channels=False, + )[0] + + +def test__set_metadata(): + """edge_test.FDSNFactory_test.test__set_metadata()""" + # Call _set_metadata with 2 traces, and make certain the stats get + # set for both traces. + trace1 = Trace() + trace2 = Trace() + stream = Stream(traces=[trace1, trace2]) + FDSNFactory()._set_metadata(stream, "ANMO", "X", "variation", "second") + assert_equal(stream[0].stats["channel"], "X") + assert_equal(stream[1].stats["channel"], "X") + + +def test_get_timeseries(FDSN_factory): + """edge_test.FDSNFactory_test.test_get_timeseries()""" + # Call get_timeseries, and test stats for comfirmation that it came back. + # TODO, need to pass in host and port from a config file, or manually + # change for a single test. + timeseries = FDSN_factory.get_timeseries( + starttime=UTCDateTime(2024, 3, 1, 0, 0, 0), + endtime=UTCDateTime(2024, 3, 1, 1, 0, 0), + observatory="ANMO", + channels=("X"), + type="variation", + interval="second", + ) + + assert_equal( + timeseries.select(channel="X")[0].stats.station, + "ANMO", + "Expect timeseries to have stats", + ) + assert_equal( + timeseries.select(channel="X")[0].stats.channel, + "X", + "Expect timeseries stats channel to be equal to X", + ) + assert_equal( + timeseries.select(channel="X")[0].stats.data_type, + "variation", + "Expect timeseries stats data_type to be equal to variation", + ) + + +def test_get_timeseries_by_location(FDSN_factory): + """test.edge_test.FDSNFactory_test.test_get_timeseries_by_location()""" + timeseries = FDSN_factory.get_timeseries( + UTCDateTime(2024, 3, 1, 0, 0, 0), + UTCDateTime(2024, 3, 1, 1, 0, 0), + "ANMO", + ("X"), + "R0", + "second", + ) + assert_equal( + timeseries.select(channel="X")[0].stats.data_type, + "R0", + "Expect timeseries stats data_type to be equal to R0", + ) + + +def test_rotate_trace(): + # Initialize the factory + factory = FDSNFactory( + observatory="ANMO", + channels=["X", "Y", "Z"], + type="variation", + interval="second", + ) + + # Simulate input traces for X, Y, Z channels + starttime = UTCDateTime("2024-01-01T00:00:00") + endtime = UTCDateTime(2024, 1, 1, 0, 10) + data_x = Trace( + data=np.array([1, 2, 3, 4, 5]), + header={"channel": "X", "starttime": starttime, "delta": 60}, + ) + data_y = Trace( + data=np.array([6, 7, 8, 9, 10]), + header={"channel": "Y", "starttime": starttime, "delta": 60}, + ) + data_z = Trace( + data=np.array([11, 12, 13, 14, 15]), + header={"channel": "Z", "starttime": starttime, "delta": 60}, + ) + input_stream = Stream(traces=[data_x, data_y, data_z]) + + # Mock the Client.get_waveforms method to return the simulated stream + factory.Client.get_waveforms = lambda *args, **kwargs: input_stream + + # Create a mock inventory object for get stations + mock_inventory = create_mock_inventory() + # Mock the Client.get_stations method to return dummy inventory (if required for rotation) + factory.Client.get_stations = lambda *args, **kwargs: mock_inventory + + # Call get_timeseries with channel "X" to trigger rotation + rotated_stream = factory.get_timeseries( + starttime=starttime, + endtime=endtime, + observatory="ANMO", + channels=["X"], # Requesting any channel in [X, Y, Z] should trigger rotation + ) + + # Assertions + assert ( + len(rotated_stream) == 1 + ), "Expected only the requested channel (X, Y, Z) after rotation" + assert rotated_stream[0].stats.channel in [ + "X", + ], "Unexpected channel names after rotation" + assert ( + rotated_stream[0].stats.starttime == starttime + ), "Start time mismatch in rotated data" + + +def create_mock_inventory(): + """Creates a mock inventory for testing purposes.""" + # Create a dummy channel + channel = Channel( + code="X", + location_code="", + latitude=0.0, + longitude=0.0, + elevation=0.0, + depth=0.0, + azimuth=0.0, + dip=0.0, + sample_rate=1.0, + ) + # Create a dummy station + station = Station( + code="ANMO", + latitude=0.0, + longitude=0.0, + elevation=0.0, + site=Site(name="TestSite"), + channels=[channel], + ) + # Create a dummy network + network = Network(code="XX", stations=[station]) + # Create an inventory + inventory = Inventory(networks=[network], source="MockInventory") + return inventory diff --git a/test/edge_test/mseed_FDSN_test_clients.py b/test/edge_test/mseed_FDSN_test_clients.py new file mode 100644 index 00000000..dcad34d2 --- /dev/null +++ b/test/edge_test/mseed_FDSN_test_clients.py @@ -0,0 +1,47 @@ +import numpy +from obspy import Stream, UTCDateTime +from obspy.clients.neic.client import Client + +from geomagio import TimeseriesUtility +from geomagio.edge import FDSNSNCL + + +class MockFDSNSeedClient(Client): + """replaces default obspy miniseed client's get_waveforms method to return trace of ones + + Note: includes 'return_empty' parameter to simulate situations where no data is received + """ + + def __init__(self, return_empty: bool = False): + self.return_empty = return_empty + + def get_waveforms( + self, + network: str, + station: str, + location: str, + channel: str, + starttime: UTCDateTime, + endtime: UTCDateTime, + ): + if self.return_empty: + return Stream() + sncl = FDSNSNCL( + station=station, + network=network, + channel=channel, + location=location, + ) + trace = TimeseriesUtility.create_empty_trace( + starttime=starttime, + endtime=endtime, + observatory=station, + channel=channel, + type=sncl.data_type, + interval=sncl.interval, + network=network, + station=station, + location=location, + ) + trace.data = numpy.ones(trace.stats.npts) + return Stream([trace]) -- GitLab From 71bcbc76e7b1294ad326d781093ac6d7dcd1a629 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Tue, 10 Dec 2024 09:38:56 -0700 Subject: [PATCH 03/10] Removed the default auto from input sampling period. Added descriptor to swagger saying that will generate correct sampling period needed to find the output_sampling_period. --- geomagio/api/ws/DataApiQuery.py | 9 --------- geomagio/api/ws/FilterApiQuery.py | 32 +------------------------------ geomagio/api/ws/algorithms.py | 7 +++---- geomagio/api/ws/filter.py | 11 +++++------ test/FilterApiQuery_test.py | 5 ++--- 5 files changed, 11 insertions(+), 53 deletions(-) diff --git a/geomagio/api/ws/DataApiQuery.py b/geomagio/api/ws/DataApiQuery.py index 5e90a33c..06fff981 100644 --- a/geomagio/api/ws/DataApiQuery.py +++ b/geomagio/api/ws/DataApiQuery.py @@ -41,15 +41,6 @@ class SamplingPeriod(float, enum.Enum): DAY = 86400.0 -class SamplingPeriodWithAuto(str, enum.Enum): - AUTO = "auto" - TEN_HERTZ = SamplingPeriod.TEN_HERTZ.value - SECOND = SamplingPeriod.SECOND.value - MINUTE = SamplingPeriod.MINUTE.value - HOUR = SamplingPeriod.HOUR.value - DAY = SamplingPeriod.DAY.value - - class DataHost(str, enum.Enum): # recognized public Edge data hosts, plus one user-specified DEFAULT = os.getenv("DATA_HOST", "edgecwb.usgs.gov") diff --git a/geomagio/api/ws/FilterApiQuery.py b/geomagio/api/ws/FilterApiQuery.py index f602fc44..0aab1c78 100644 --- a/geomagio/api/ws/FilterApiQuery.py +++ b/geomagio/api/ws/FilterApiQuery.py @@ -2,7 +2,6 @@ from .DataApiQuery import ( DataApiQuery, SamplingPeriod, REQUEST_LIMIT, - SamplingPeriodWithAuto, ) from pydantic import ConfigDict, model_validator, field_validator from typing import Optional, Union @@ -14,36 +13,7 @@ the fields input_sampling_period and output_sampling_period.""" class FilterApiQuery(DataApiQuery): model_config = ConfigDict(extra="forbid") - input_sampling_period: Union[SamplingPeriodWithAuto, float] = ( - SamplingPeriodWithAuto.AUTO - ) - - @field_validator("input_sampling_period", mode="before") - def normalize_sampling_period(cls, value): - if isinstance(value, str) and value == SamplingPeriodWithAuto.AUTO: - return float("nan") # Map 'auto' to NaN internally - if isinstance(value, str): - return float(value) # Map string values to float - try: - value = float(value) # Coerce numeric-like strings to float - except ValueError: - raise ValueError( - f"Invalid sampling period. Must be one of " - f"{[item.value for item in SamplingPeriodWithAuto]}" - ) - # If the value is a float, find its matching enum based on the string value - if isinstance(value, float): - print("The sampling period is touching this logic downstream", type(value)) - # Find matching enum value by checking if the float matches the string equivalent but skip the string "auto" - for period in list(SamplingPeriodWithAuto)[1:]: - if float(period.value) == value: - - return period - - # If no match is found, return the float as-is - return value - - return value # Return the value if it's not a recognized string or float + input_sampling_period: Optional[Union[SamplingPeriod, float]] = None @model_validator(mode="after") def validate_sample_size(self): diff --git a/geomagio/api/ws/algorithms.py b/geomagio/api/ws/algorithms.py index 879ac70c..25d2f013 100644 --- a/geomagio/api/ws/algorithms.py +++ b/geomagio/api/ws/algorithms.py @@ -2,15 +2,14 @@ import json from fastapi import APIRouter, Depends, HTTPException, Query from starlette.responses import Response -from obspy.core import Stream, Stats -from typing import List, Union -from ...algorithm import DbDtAlgorithm, FilterAlgorithm + +from ...algorithm import DbDtAlgorithm from ...residual import ( calculate, Reading, ) -from .DataApiQuery import DataApiQuery, SamplingPeriod +from .DataApiQuery import DataApiQuery from .FilterApiQuery import FilterApiQuery from .data import format_timeseries, get_data_factory, get_data_query, get_timeseries from .filter import get_filter_data_query diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 234aaa7c..95853f86 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -11,7 +11,6 @@ from .DataApiQuery import ( DataType, OutputFormat, SamplingPeriod, - SamplingPeriodWithAuto, ) from .FilterApiQuery import FilterApiQuery from ...algorithm.FilterAlgorithm import STEPS @@ -34,13 +33,13 @@ def get_filter_data_query( format: Union[OutputFormat, str] = Query( OutputFormat.IAGA2002, title="Output Format" ), - input_sampling_period: Union[SamplingPeriodWithAuto, float, int] = Query( - SamplingPeriodWithAuto.AUTO, # Assign Default value as auto + input_sampling_period: Optional[Union[SamplingPeriod, float]] = Query( + None, title="Initial Sampling Period", - description="Auto will dynamically determine necessary input_sampling_period.", + description="`--` dynamically determines a necessary sampling period.", ), sampling_period: Union[SamplingPeriod, float] = Query( - SamplingPeriod, alias="output_sampling_period", title="Output sampling period" + SamplingPeriod.SECOND, alias="output_sampling_period", title="Output sampling period" ), data_host: Union[DataHost, str] = Query( DataHost.DEFAULT, title="Data Host", description="Edge host to pull data from." @@ -66,7 +65,7 @@ def get_timeseries(query: FilterApiQuery) -> Stream: # Determine input sampling period if not provided # if query.input_sampling_period == SamplingPeriodWithAuto.AUTO or query.input_sampling_period is None: - if math.isnan(query.input_sampling_period) or query.input_sampling_period is None: + if query.input_sampling_period is None: # Dynamically determine the input sampling period input_sampling_period, data = determine_available_period( query.sampling_period, query, data_factory diff --git a/test/FilterApiQuery_test.py b/test/FilterApiQuery_test.py index 1c7c3845..b6a4dc04 100644 --- a/test/FilterApiQuery_test.py +++ b/test/FilterApiQuery_test.py @@ -5,7 +5,6 @@ from obspy import UTCDateTime from geomagio.api.ws.FilterApiQuery import FilterApiQuery from geomagio.api.ws.DataApiQuery import ( SamplingPeriod, - SamplingPeriodWithAuto, DataType, OutputFormat, DataHost, @@ -23,7 +22,7 @@ def test_FilterApiQuery_defaults(): assert_equal(query.starttime, expected_start_time) assert_equal(query.endtime, expected_endtime) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.input_sampling_period, SamplingPeriodWithAuto.AUTO) + assert_equal(query.input_sampling_period, None) assert_equal(query.sampling_period, SamplingPeriod.MINUTE) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) @@ -47,7 +46,7 @@ def test_FilterApiQuery_valid(): assert_equal(query.starttime, UTCDateTime("2024-09-01T00:00:01")) assert_equal(query.endtime, UTCDateTime("2024-09-01T01:00:01")) assert_equal(query.elements, ["Z"]) - assert_equal(query.input_sampling_period, SamplingPeriodWithAuto.MINUTE) + assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) assert_equal(query.sampling_period, SamplingPeriod.HOUR) assert_equal(query.data_type, DataType.ADJUSTED) assert_equal(query.format, OutputFormat.JSON) -- GitLab From daaaf265cd1a648e4367b36be7c1fb127585050c Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Tue, 10 Dec 2024 09:55:29 -0700 Subject: [PATCH 04/10] Ran lint --- geomagio/api/ws/filter.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 95853f86..11c24dd0 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -39,7 +39,9 @@ def get_filter_data_query( description="`--` dynamically determines a necessary sampling period.", ), sampling_period: Union[SamplingPeriod, float] = Query( - SamplingPeriod.SECOND, alias="output_sampling_period", title="Output sampling period" + SamplingPeriod.SECOND, + alias="output_sampling_period", + title="Output sampling period", ), data_host: Union[DataHost, str] = Query( DataHost.DEFAULT, title="Data Host", description="Edge host to pull data from." -- GitLab From e930e859b9ea50773b085c203b74c6c9a751480f Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Tue, 10 Dec 2024 11:46:44 -0700 Subject: [PATCH 05/10] Reverted test to allow strings for specifc parmaters. I believe I grabbed an old version of DataAPIQuery that caused the test to fail before. Things should now be up to date. --- geomagio/api/ws/DataApiQuery.py | 6 +++--- test/DataApiQuery_test.py | 6 +++--- test/FilterApiQuery_test.py | 6 +++--- test/api_test/ws_test/data_test.py | 4 ++-- test/api_test/ws_test/filter_test.py | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/geomagio/api/ws/DataApiQuery.py b/geomagio/api/ws/DataApiQuery.py index 06fff981..3d7a71c4 100644 --- a/geomagio/api/ws/DataApiQuery.py +++ b/geomagio/api/ws/DataApiQuery.py @@ -70,9 +70,9 @@ class DataApiQuery(BaseModel): endtime: Optional[CustomUTCDateTimeType] = None elements: List[str] = DEFAULT_ELEMENTS sampling_period: SamplingPeriod = SamplingPeriod.MINUTE - data_type: DataType = DataType.VARIATION - format: OutputFormat = OutputFormat.IAGA2002 - data_host: DataHost = DataHost.DEFAULT + data_type: Union[DataType, str] = DataType.VARIATION + format: Union[OutputFormat, str] = OutputFormat.IAGA2002 + data_host: Union[DataHost, str] = DataHost.DEFAULT @field_validator("starttime", mode="before") def validate_starttime( diff --git a/test/DataApiQuery_test.py b/test/DataApiQuery_test.py index 4434af7d..117f1758 100644 --- a/test/DataApiQuery_test.py +++ b/test/DataApiQuery_test.py @@ -65,9 +65,9 @@ def test_DataApiQuery_valid(): assert_equal(query.endtime, UTCDateTime("2024-09-01T01:00:01")) assert_equal(query.elements, ["F"]) assert_equal(query.sampling_period, SamplingPeriod.SECOND) - assert_equal(query.data_type, DataType.ADJUSTED) - assert_equal(query.format, OutputFormat.JSON) - assert_equal(query.data_host, DataHost.CWBPUB) + assert_equal(query.data_type, "adjusted") + assert_equal(query.format, "json") + assert_equal(query.data_host, "cwbpub.cr.usgs.gov") def test_DataApiQuery_no_id(): diff --git a/test/FilterApiQuery_test.py b/test/FilterApiQuery_test.py index b6a4dc04..6393297a 100644 --- a/test/FilterApiQuery_test.py +++ b/test/FilterApiQuery_test.py @@ -48,9 +48,9 @@ def test_FilterApiQuery_valid(): assert_equal(query.elements, ["Z"]) assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) assert_equal(query.sampling_period, SamplingPeriod.HOUR) - assert_equal(query.data_type, DataType.ADJUSTED) - assert_equal(query.format, OutputFormat.JSON) - assert_equal(query.data_host, DataHost.CWBPUB) + assert_equal(query.data_type, "adjusted") + assert_equal(query.format, "json") + assert_equal(query.data_host, "cwbpub.cr.usgs.gov") def test_FilterApiQuery_no_id(): diff --git a/test/api_test/ws_test/data_test.py b/test/api_test/ws_test/data_test.py index 96fba2f0..9a3da337 100644 --- a/test/api_test/ws_test/data_test.py +++ b/test/api_test/ws_test/data_test.py @@ -36,8 +36,8 @@ def test_get_data_query(test_client): assert_equal(query.endtime, UTCDateTime("2020-09-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) assert_equal(query.sampling_period, SamplingPeriod.MINUTE) - assert_equal(query.format, OutputFormat.IAGA2002) - assert_equal(query.data_type, DataType.VARIATION) + assert_equal(query.format, "iaga2002") + assert_equal(query.data_type, "variation") def test_get_data_query_no_starttime(test_client): diff --git a/test/api_test/ws_test/filter_test.py b/test/api_test/ws_test/filter_test.py index 470e8474..aa0a4d8f 100644 --- a/test/api_test/ws_test/filter_test.py +++ b/test/api_test/ws_test/filter_test.py @@ -31,8 +31,8 @@ def test_get_filter_data_query(test_client): assert_equal(query.starttime, UTCDateTime("2020-09-01T00:00:01")) assert_equal(query.endtime, UTCDateTime("2020-09-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.format, OutputFormat.IAGA2002) - assert_equal(query.data_type, DataType.VARIATION) + assert_equal(query.format, "iaga2002") + assert_equal(query.data_type, "variation") assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) assert_equal(query.output_sampling_period, SamplingPeriod.HOUR) -- GitLab From d0f94b4dff63364cb35de23b50c3edb398c01838 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Wed, 11 Dec 2024 10:38:06 -0700 Subject: [PATCH 06/10] Removed union method from FilterApiQuery and Filter.py, I also added a negatvie test to filter_test to account check that an innapropriate float would cause and error. I also removed the asyn functions from data_test.py because they were being skipped in the testing pipeline. I made them regular function and they are now passing. --- geomagio/api/ws/FilterApiQuery.py | 2 +- geomagio/api/ws/filter.py | 4 ++-- poetry.lock | 2 +- test/api_test/ws_test/data_test.py | 30 +++++----------------------- test/api_test/ws_test/filter_test.py | 1 + 5 files changed, 10 insertions(+), 29 deletions(-) diff --git a/geomagio/api/ws/FilterApiQuery.py b/geomagio/api/ws/FilterApiQuery.py index 0aab1c78..ee2a80bc 100644 --- a/geomagio/api/ws/FilterApiQuery.py +++ b/geomagio/api/ws/FilterApiQuery.py @@ -13,7 +13,7 @@ the fields input_sampling_period and output_sampling_period.""" class FilterApiQuery(DataApiQuery): model_config = ConfigDict(extra="forbid") - input_sampling_period: Optional[Union[SamplingPeriod, float]] = None + input_sampling_period: Optional[SamplingPeriod] = None @model_validator(mode="after") def validate_sample_size(self): diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 11c24dd0..ef0b824a 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -33,12 +33,12 @@ def get_filter_data_query( format: Union[OutputFormat, str] = Query( OutputFormat.IAGA2002, title="Output Format" ), - input_sampling_period: Optional[Union[SamplingPeriod, float]] = Query( + input_sampling_period: Optional[SamplingPeriod] = Query( None, title="Initial Sampling Period", description="`--` dynamically determines a necessary sampling period.", ), - sampling_period: Union[SamplingPeriod, float] = Query( + sampling_period: SamplingPeriod = Query( SamplingPeriod.SECOND, alias="output_sampling_period", title="Output sampling period", diff --git a/poetry.lock b/poetry.lock index d2d17532..95155b3c 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. [[package]] name = "aiomysql" diff --git a/test/api_test/ws_test/data_test.py b/test/api_test/ws_test/data_test.py index 9a3da337..765fa407 100644 --- a/test/api_test/ws_test/data_test.py +++ b/test/api_test/ws_test/data_test.py @@ -57,38 +57,18 @@ def test_get_data_query_no_starttime(test_client): async def test_get_data_query_extra_params(test_client): with pytest.raises(ValueError) as error: - response = await test_client.get( + response = test_client.get( "/query/?id=BOU&starttime=2020-09-01T00:00:01&elements=X,Y,Z,F&type=variation&sampling_period=60&format=iaga2002&location=R1&network=NT" ) + DataApiQuery(**response.json()) assert error.match("Invalid query parameter(s): location, network") -# def test_get_data_query_extra_params(test_client): -# """test.api_test.ws_test.data_test.test_get_data_query_extra_params()""" -# with pytest.raises(ValueError) as error: -# test_client.get( -# "/query/?id=BOU&starttime=2020-09-01T00:00:01&elements=X,Y,Z,F&type=variation&sampling_period=60&format=iaga2002&location=R1&network=NT" -# ) -# assert error.message == "Invalid query parameter(s): location, network" - - -async def test_get_data_query_bad_params(test_client): +def test_get_data_query_bad_params(test_client): """test.api_test.ws_test.data_test.test_get_data_query_bad_params()""" with pytest.raises(ValueError) as error: - response = await test_client.get( + response = test_client.get( "/query/?id=BOU&startime=2020-09-01T00:00:01&elements=X,Y,Z,F&data_type=variation&sampling_period=60&format=iaga2002" ) + DataApiQuery(**response.json()) assert error.match == "Invalid query parameter(s): startime, data_type" - - -# def test_filter_data_query(test_client): -# """test.api_test.ws_test.data_test.test_filter_data_query()""" -# response = test_client.get( -# "/algorithms/filter/?id=BOU&starttime=2020-09-01T00:00:01&elements=X,Y,Z,F&type=R1&sampling_period=60&format=iaga2002&input_sampling_period=60&output_sampling_period=30" -# ) -# filter_query = FilterDataApiQuery(**response.json()) -# assert_equal(filter_query.id, "BOU") -# assert_equal(filter_query.starttime, UTCDateTime("2020-09-01T00:00:01")) -# assert_equal(filter_query.elements, ["X", "Y", "Z", "F"]) -# assert_equal(filter_query.input_sampling_period, 60) -# assert_equal(filter_query.output_sampling_period, 30) diff --git a/test/api_test/ws_test/filter_test.py b/test/api_test/ws_test/filter_test.py index aa0a4d8f..d56b6352 100644 --- a/test/api_test/ws_test/filter_test.py +++ b/test/api_test/ws_test/filter_test.py @@ -3,6 +3,7 @@ from fastapi import Depends from fastapi.testclient import TestClient from numpy.testing import assert_equal from obspy import UTCDateTime +from pydantic import ValidationError import pytest from geomagio.api.ws import app -- GitLab From f8103bfc8ca8341aba026f2119d8c67f88158fa5 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Wed, 11 Dec 2024 11:31:23 -0700 Subject: [PATCH 07/10] Fixed the test. --- geomagio/api/ws/FilterApiQuery.py | 4 ++-- test/api_test/ws_test/filter_test.py | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/geomagio/api/ws/FilterApiQuery.py b/geomagio/api/ws/FilterApiQuery.py index ee2a80bc..2524a7fd 100644 --- a/geomagio/api/ws/FilterApiQuery.py +++ b/geomagio/api/ws/FilterApiQuery.py @@ -3,8 +3,8 @@ from .DataApiQuery import ( SamplingPeriod, REQUEST_LIMIT, ) -from pydantic import ConfigDict, model_validator, field_validator -from typing import Optional, Union +from pydantic import ConfigDict, model_validator, field_validator, ValidationError +from typing import Optional """This class inherits all the fields and validation on DataApiQuery and adds the fields input_sampling_period and output_sampling_period.""" diff --git a/test/api_test/ws_test/filter_test.py b/test/api_test/ws_test/filter_test.py index d56b6352..aa0a4d8f 100644 --- a/test/api_test/ws_test/filter_test.py +++ b/test/api_test/ws_test/filter_test.py @@ -3,7 +3,6 @@ from fastapi import Depends from fastapi.testclient import TestClient from numpy.testing import assert_equal from obspy import UTCDateTime -from pydantic import ValidationError import pytest from geomagio.api.ws import app -- GitLab From dfd52e5028d2f35c0719ebe8686a883451aee288 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Tue, 7 Jan 2025 13:31:30 -0700 Subject: [PATCH 08/10] Updated the filter endpoint to not allow for the output sampling period to be none. If it is left empty an error code wil prompt you to provide an appropriate sampling period. This involved adding some logic to a few of the test and a couple logger warming that would skip trying to determine wehter the number of smaple reqeusted ignores the sample request limit. --- geomagio/api/ws/DataApiQuery.py | 32 ++- geomagio/api/ws/FilterApiQuery.py | 32 ++- geomagio/api/ws/algorithms.py | 1 - geomagio/api/ws/data.py | 2 +- geomagio/api/ws/filter.py | 22 +- poetry.lock | 290 +++++++++++++-------------- pytest.ini | 6 + test/DataApiQuery_test.py | 8 +- test/FilterApiQuery_test.py | 14 +- test/api_test/ws_test/filter_test.py | 2 +- 10 files changed, 220 insertions(+), 189 deletions(-) diff --git a/geomagio/api/ws/DataApiQuery.py b/geomagio/api/ws/DataApiQuery.py index 3d7a71c4..5dd2102a 100644 --- a/geomagio/api/ws/DataApiQuery.py +++ b/geomagio/api/ws/DataApiQuery.py @@ -10,8 +10,12 @@ from pydantic import ConfigDict, field_validator, model_validator, Field, BaseMo from .Element import ELEMENTS from .Observatory import OBSERVATORY_INDEX, ASL_OBSERVATORY_INDEX from ...pydantic_utcdatetime import CustomUTCDateTimeType +import logging - +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", +) DEFAULT_ELEMENTS = ["X", "Y", "Z", "F"] REQUEST_LIMIT = 3456000 # Increased the request limit by 10x what was decided by Jeremy VALID_ELEMENTS = [e.id for e in ELEMENTS] @@ -69,7 +73,7 @@ class DataApiQuery(BaseModel): # endtime default is dependent on start time, so it's handled after validation in the model_validator endtime: Optional[CustomUTCDateTimeType] = None elements: List[str] = DEFAULT_ELEMENTS - sampling_period: SamplingPeriod = SamplingPeriod.MINUTE + sampling_period: Optional[SamplingPeriod] = None data_type: Union[DataType, str] = DataType.VARIATION format: Union[OutputFormat, str] = OutputFormat.IAGA2002 data_host: Union[DataHost, str] = DataHost.DEFAULT @@ -124,11 +128,21 @@ class DataApiQuery(BaseModel): self.endtime = self.starttime + (86400 - 0.001) if self.starttime > self.endtime: raise ValueError("Starttime must be before endtime.") - # check data volume - samples = int( - len(self.elements) * (self.endtime - self.starttime) / self.sampling_period - ) - if samples > REQUEST_LIMIT: - raise ValueError(f"Request exceeds limit ({samples} > {REQUEST_LIMIT})") - # otherwise okay + + # check data volume and if SamplingPeriod is assigned as None + if self.sampling_period is None: + logging.warning( + "Sampling period is None. Default value or further processing needed." + ) + # self.sampling_period = 0.0 + + else: + samples = int( + len(self.elements) + * (self.endtime - self.starttime) + / self.sampling_period + ) + if samples > REQUEST_LIMIT: + raise ValueError(f"Request exceeds limit ({samples} > {REQUEST_LIMIT})") + # otherwise okay return self diff --git a/geomagio/api/ws/FilterApiQuery.py b/geomagio/api/ws/FilterApiQuery.py index 2524a7fd..cee262d9 100644 --- a/geomagio/api/ws/FilterApiQuery.py +++ b/geomagio/api/ws/FilterApiQuery.py @@ -5,6 +5,13 @@ from .DataApiQuery import ( ) from pydantic import ConfigDict, model_validator, field_validator, ValidationError from typing import Optional +import logging +from fastapi import HTTPException + +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", +) """This class inherits all the fields and validation on DataApiQuery and adds the fields input_sampling_period and output_sampling_period.""" @@ -17,13 +24,22 @@ class FilterApiQuery(DataApiQuery): @model_validator(mode="after") def validate_sample_size(self): - # Calculate the number of samples based on the input sampling period - samples = int( - len(self.elements) * (self.endtime - self.starttime) / self.sampling_period - ) - - # Validate the request size - if samples > REQUEST_LIMIT: - raise ValueError(f"Request exceeds limit ({samples} > {REQUEST_LIMIT})") + if self.sampling_period is None: + # Log a warning indicating that the sampling period is missing + logging.warning( + "Sampling period is None. Please provide a valid Sampling Period." + ) + + else: + # Calculate the number of samples based on the input sampling period + samples = int( + len(self.elements) + * (self.endtime - self.starttime) + / self.sampling_period + ) + + # Validate the request size + if samples > REQUEST_LIMIT: + raise ValueError(f"Request exceeds limit ({samples} > {REQUEST_LIMIT})") return self diff --git a/geomagio/api/ws/algorithms.py b/geomagio/api/ws/algorithms.py index 25d2f013..c4696a4c 100644 --- a/geomagio/api/ws/algorithms.py +++ b/geomagio/api/ws/algorithms.py @@ -14,7 +14,6 @@ from .FilterApiQuery import FilterApiQuery from .data import format_timeseries, get_data_factory, get_data_query, get_timeseries from .filter import get_filter_data_query from . import filter -from ...algorithm.FilterAlgorithm import STEPS import logging logger = logging.getLogger(__name__) diff --git a/geomagio/api/ws/data.py b/geomagio/api/ws/data.py index 3a77dbb8..1eb735fd 100644 --- a/geomagio/api/ws/data.py +++ b/geomagio/api/ws/data.py @@ -74,7 +74,7 @@ def get_data_query( " NOTE: when using 'iaga2002' output format, a maximum of 4 elements is allowed", ), sampling_period: Union[SamplingPeriod, float] = Query( - SamplingPeriod.MINUTE, + None, title="data rate", description="Interval in seconds between values.", ), diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index ef0b824a..5d5ae85b 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -35,11 +35,11 @@ def get_filter_data_query( ), input_sampling_period: Optional[SamplingPeriod] = Query( None, - title="Initial Sampling Period", + title="Input Sampling Period", description="`--` dynamically determines a necessary sampling period.", ), - sampling_period: SamplingPeriod = Query( - SamplingPeriod.SECOND, + sampling_period: Optional[SamplingPeriod] = Query( + None, alias="output_sampling_period", title="Output sampling period", ), @@ -66,7 +66,6 @@ def get_timeseries(query: FilterApiQuery) -> Stream: data_factory = get_data_factory(query=query) # Determine input sampling period if not provided - # if query.input_sampling_period == SamplingPeriodWithAuto.AUTO or query.input_sampling_period is None: if query.input_sampling_period is None: # Dynamically determine the input sampling period input_sampling_period, data = determine_available_period( @@ -79,7 +78,7 @@ def get_timeseries(query: FilterApiQuery) -> Stream: input_sample_period=input_sampling_period, output_sample_period=query.sampling_period, ) - # Fetch data + # Fetch filtered data starttime, endtime = filt.get_input_interval(query.starttime, query.endtime) data = data_factory.get_timeseries( @@ -91,7 +90,8 @@ def get_timeseries(query: FilterApiQuery) -> Stream: interval=TimeseriesUtility.get_interval_from_delta(filt.input_sample_period), ) - # Apply filtering + # Apply filtering if needed + filtered_timeseries = filt.process(data) return filtered_timeseries @@ -106,9 +106,13 @@ def determine_available_period(output_sampling_period: float, query, data_factor sorted_periods: List[SamplingPeriod] = sorted( SamplingPeriod, key=lambda p: p.value, reverse=True ) - valid_sampling_periods = [ - p for p in sorted_periods if p.value <= output_sampling_period - ] + if output_sampling_period is None: + raise ValueError("Output sampling period cannot be None.") + else: + + valid_sampling_periods = [ + p for p in sorted_periods if p.value <= output_sampling_period + ] for period in valid_sampling_periods: if period <= output_sampling_period: diff --git a/poetry.lock b/poetry.lock index 95155b3c..2976e14e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -154,13 +154,13 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2024.8.30" +version = "2024.12.14" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, - {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] @@ -244,127 +244,114 @@ pycparser = "*" [[package]] name = "charset-normalizer" -version = "3.4.0" +version = "3.4.1" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, - {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, - {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, - {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, - {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, - {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, - {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, - {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, - {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, - {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, +python-versions = ">=3.7" +files = [ + {file = "charset_normalizer-3.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win32.whl", hash = "sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f"}, + {file = "charset_normalizer-3.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win32.whl", hash = "sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b"}, + {file = "charset_normalizer-3.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win32.whl", hash = "sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35"}, + {file = "charset_normalizer-3.4.1-cp312-cp312-win_amd64.whl", hash = "sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win32.whl", hash = "sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407"}, + {file = "charset_normalizer-3.4.1-cp313-cp313-win_amd64.whl", hash = "sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win32.whl", hash = "sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487"}, + {file = "charset_normalizer-3.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win32.whl", hash = "sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e"}, + {file = "charset_normalizer-3.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win32.whl", hash = "sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5"}, + {file = "charset_normalizer-3.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765"}, + {file = "charset_normalizer-3.4.1-py3-none-any.whl", hash = "sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85"}, + {file = "charset_normalizer-3.4.1.tar.gz", hash = "sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, ] [package.dependencies] @@ -1882,47 +1869,42 @@ files = [ [[package]] name = "pycurl" -version = "7.45.3" +version = "7.45.4" description = "PycURL -- A Python Interface To The cURL library" optional = true python-versions = ">=3.5" files = [ - {file = "pycurl-7.45.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:86f66d334deaaab20a576fb785587566081407adc703318203fe26e43277ef12"}, - {file = "pycurl-7.45.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:205983e87d6aa0b6e93ec7320060de44efaa905ecc5d13f70cbe38c65684c5c4"}, - {file = "pycurl-7.45.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbd4a6b8654b779089c5a44af1c65c1419c2cd60718780df6d8f354eb35d6d55"}, - {file = "pycurl-7.45.3-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:5ebc6a0ac60c371a9efaf7d55dec5820f76fdafb43a3be1e390011339dc329ae"}, - {file = "pycurl-7.45.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:2facab1c35600088cb82b5b093bd700bfbd1e3191deab24f7d1803d9dc5b76fc"}, - {file = "pycurl-7.45.3-cp310-cp310-win32.whl", hash = "sha256:7cfca02d70579853041063e53ca713d31161b8831b98d4f68c3554dc0448beec"}, - {file = "pycurl-7.45.3-cp310-cp310-win_amd64.whl", hash = "sha256:8451e8475051f16eb4776380384699cb8ddd10ea8410bcbfaee5a6fc4c046de6"}, - {file = "pycurl-7.45.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:1610cc45b5bc8b39bc18b981d0473e59ef41226ee467eaa8fbfc7276603ef5af"}, - {file = "pycurl-7.45.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c854885398410fa6e88fc29f7a420a3c13b88bae9b4e10a804437b582e24f58b"}, - {file = "pycurl-7.45.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:921c9db0c3128481954f625b3b1bc10c730100aa944d54643528f716676439ee"}, - {file = "pycurl-7.45.3-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:483f3aa5d1bc8cff5657ad96f68e1d89281f971a7b6aa93408a31e3199981ea9"}, - {file = "pycurl-7.45.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1e0d32d6ed3a7ba13dbbd3a6fb50ca76c40c70e6bc6fe347f90677478d3422c7"}, - {file = "pycurl-7.45.3-cp311-cp311-win32.whl", hash = "sha256:beaaa4450e23d41dd0c2f2f47a4f8a171210271543550c2c556090c7eeea88f5"}, - {file = "pycurl-7.45.3-cp311-cp311-win_amd64.whl", hash = "sha256:dd33fd9de8907a6275c70113124aeb7eea672c1324f5d5423f203738b341697d"}, - {file = "pycurl-7.45.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0c41a172d5e8a5cdd8328cc8134f47b2a57960ac677f7cda8520eaa9fbe7d990"}, - {file = "pycurl-7.45.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:13006b62c157bb4483c58e1abdced6df723c9399255a4f5f6bb7f8e425106679"}, - {file = "pycurl-7.45.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:27f4c5c20c86a9a823677316724306fb1ce3b25ec568efd52026dc6c563e5b29"}, - {file = "pycurl-7.45.3-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:c2c246bc29e8762ff4c8a833ac5b4da4c797d16ab138286e8aec9b0c0a0da2d4"}, - {file = "pycurl-7.45.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:3d07c5daef2d0d85949e32ec254ee44232bb57febb0634194379dd14d1ff4f87"}, - {file = "pycurl-7.45.3-cp312-cp312-win32.whl", hash = "sha256:9f7afe5ef0e4750ac4515baebc251ee94aaefe5de6e2e8a24668473128d69904"}, - {file = "pycurl-7.45.3-cp312-cp312-win_amd64.whl", hash = "sha256:3648ed9a57a6b704673faeab3dc64d1469cc69f2bc1ed8227ffa0f84e147c500"}, - {file = "pycurl-7.45.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:c0915ea139f66a289edc4f9de10cb45078af1bb950491c5612969864236a2e7e"}, - {file = "pycurl-7.45.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:43c5e61a58783ddf78ef84949f6bb6e52e092a13ec67678e9a9e21071ecf5b80"}, - {file = "pycurl-7.45.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bf613844a1647fe3d2bba1f5c9c96a62a85280123a57a8a0c8d2f37d518bc10a"}, - {file = "pycurl-7.45.3-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:936afd9c5ff7fe7457065e878a279811787778f472f9a4e8c5df79e7728358e2"}, - {file = "pycurl-7.45.3-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:dbf816a6d0cb71e7fd06609246bbea4eaf100649d9decf49e4eb329594f70be7"}, - {file = "pycurl-7.45.3-cp38-cp38-win32.whl", hash = "sha256:2c8a2ce568193f9f84763717d8961cec0db4ec1aa08c6bcf4d90da5eb72bec86"}, - {file = "pycurl-7.45.3-cp38-cp38-win_amd64.whl", hash = "sha256:80ac7c17e69ca6b76ccccb4255f7c29a2a36e5b69eb10c2adba82135d43afe8c"}, - {file = "pycurl-7.45.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:fa7751b614d9aa82d7a0f49ca90924c29c6cedf85a2f8687fb6a772dbfe48711"}, - {file = "pycurl-7.45.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b129e9ee07f80b4af957607917af46ab517b0c4e746692f6d9e50e973edba8d8"}, - {file = "pycurl-7.45.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a0f920582b8713ca87d5a288a7532607bc4454275d733fc880650d602dbe3c67"}, - {file = "pycurl-7.45.3-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:c7c13e4268550cde14a6f4743cc8bd8c035d4cd36514d58eff70276d68954b6f"}, - {file = "pycurl-7.45.3-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:0f0e1251a608ffd75fc502f4014442e554c67d3d7a1b0a839c35efb6ad2f8bf8"}, - {file = "pycurl-7.45.3-cp39-cp39-win32.whl", hash = "sha256:51a40a56c58e63dac6145829f9e9bd66e5867a9f0741bcb9ffefab619851d44f"}, - {file = "pycurl-7.45.3-cp39-cp39-win_amd64.whl", hash = "sha256:e08a06802c8c8a9d04cf3319f9230ec09062c55d2550bd48f8ada1df1431adcf"}, - {file = "pycurl-7.45.3.tar.gz", hash = "sha256:8c2471af9079ad798e1645ec0b0d3d4223db687379d17dd36a70637449f81d6b"}, + {file = "pycurl-7.45.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:247b4af8eab7d04137a7f1a98391930e04ea93dc669b64db5625070fe15f80a3"}, + {file = "pycurl-7.45.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:561f88697f7540634b1c750146f37bdc0da367b15f6b4ab2bb780871ee6ab005"}, + {file = "pycurl-7.45.4-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:b485fdaf78553f0b8e1c2803bb7dcbe47a7b47594f846fc7e9d3b94d794cfc89"}, + {file = "pycurl-7.45.4-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e7ae49b88a5d57485fbabef004534225dfe04dc15716a61fae1a0c7f46f2279e"}, + {file = "pycurl-7.45.4-cp310-cp310-win32.whl", hash = "sha256:d14f954ecd21a070038d65ef1c6d1d3ab220f952ff703d48313123222097615c"}, + {file = "pycurl-7.45.4-cp310-cp310-win_amd64.whl", hash = "sha256:2548c3291a33c821f0f80bf9989fc43b5d90fb78b534a7015c8419b83c6f5803"}, + {file = "pycurl-7.45.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:f6c0e22052946bbfa25be67f9d1d6639eff10781c89f0cf6f3ff2099273d1bad"}, + {file = "pycurl-7.45.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:acf25cfdaf914db21a2a6e9e274b6d95e3fa2b6018c38f2c58c94b5d8ac3d1b7"}, + {file = "pycurl-7.45.4-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:a39f28f031885485325034918386be352036c220ca45625c7e286d3938eb579d"}, + {file = "pycurl-7.45.4-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:9940e3234c1ca3d30f27a2202d325dbc25291605c98e9585100a351cacd935e8"}, + {file = "pycurl-7.45.4-cp311-cp311-win32.whl", hash = "sha256:ffd3262f98b8997ad04940061d5ebd8bab2362169b9440939c397e24a4a135b0"}, + {file = "pycurl-7.45.4-cp311-cp311-win_amd64.whl", hash = "sha256:1324a859b50bdb0abdbd5620e42f74240d0b7daf2d5925fa303695d9fc3ece18"}, + {file = "pycurl-7.45.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:731c46e7c0acffaab19f7c2ecc3d9e7ee337500e87b260b4e0b9fae2d90fa133"}, + {file = "pycurl-7.45.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13eb1643ab0bf4fdc539a2cdf1021029b07095d3196c5cee5a4271af268d3d31"}, + {file = "pycurl-7.45.4-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:df5f94c051c5a163fa85064559ca94979575e2da26740ff91c078c50c541c465"}, + {file = "pycurl-7.45.4-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:688d09ba2c6a0d4a749d192c43422839d73c40c85143c50cc65c944258fe0ba8"}, + {file = "pycurl-7.45.4-cp312-cp312-win32.whl", hash = "sha256:236600bfe2cd72efe47333add621286667e8fa027dadf1247349afbf30333e95"}, + {file = "pycurl-7.45.4-cp312-cp312-win_amd64.whl", hash = "sha256:26745c6c5ebdccfe8a828ac3fd4e6da6f5d2245696604f04529eb7894a02f4db"}, + {file = "pycurl-7.45.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9bd493ce598f1dc76c8e50043c47debec27c583fa313a836b2d3667640f875d5"}, + {file = "pycurl-7.45.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:4f25d52c97dbca6ebea786f0961b49c1998fa05178abf1964a977c825b3d8ae6"}, + {file = "pycurl-7.45.4-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:13c4b18f44637859f34639493efd297a08670f45e4eec34ab2dcba724e3cb5fc"}, + {file = "pycurl-7.45.4-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:0470bff6cc24d8c2f63c80931aa239463800871609dafc6bcc9ca10f5a12a04e"}, + {file = "pycurl-7.45.4-cp313-cp313-win32.whl", hash = "sha256:3452459668bd01d646385482362b021834a31c036aa1c02acd88924ddeff7d0d"}, + {file = "pycurl-7.45.4-cp313-cp313-win_amd64.whl", hash = "sha256:fd167f73d34beb0cb8064334aee76d9bdd13167b30be6d5d36fb07d0c8223b71"}, + {file = "pycurl-7.45.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b0e38e3eb83b0c891f391853f798fc6a97cb5a86a4a731df0b6320e539ae54ae"}, + {file = "pycurl-7.45.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d192a48b3cec2e13ad432196b65c22e99620db92feae39c0476635354eff68c6"}, + {file = "pycurl-7.45.4-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:57971d7215fc6fdedcfc092f880a59f04f52fcaf2fd329151b931623d7b59a9c"}, + {file = "pycurl-7.45.4-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:73df3eb5940a7fbf4cf62f7271e9f23a8e9f80e352c838ee9a8448a70c01d3f5"}, + {file = "pycurl-7.45.4-cp39-cp39-win32.whl", hash = "sha256:587a4891039803b5f48392066f97b7cd5e7e9a166187abb5cb4b4806fdb8fbef"}, + {file = "pycurl-7.45.4-cp39-cp39-win_amd64.whl", hash = "sha256:caec8b634763351dd4e1b729a71542b1e2de885d39710ba8e7202817a381b453"}, + {file = "pycurl-7.45.4.tar.gz", hash = "sha256:32c8e237069273f4260b6ae13d1e0f99daae938977016021565dc6e11050e803"}, ] [[package]] @@ -2280,13 +2262,13 @@ idna2008 = ["idna"] [[package]] name = "ruamel-yaml" -version = "0.18.6" +version = "0.18.10" description = "ruamel.yaml is a YAML parser/emitter that supports roundtrip preservation of comments, seq/map flow style, and map key order" optional = false python-versions = ">=3.7" files = [ - {file = "ruamel.yaml-0.18.6-py3-none-any.whl", hash = "sha256:57b53ba33def16c4f3d807c0ccbc00f8a6081827e81ba2491691b76882d0c636"}, - {file = "ruamel.yaml-0.18.6.tar.gz", hash = "sha256:8b27e6a217e786c6fbe5634d8f3f11bc63e0f80f6a5890f28863d9c45aac311b"}, + {file = "ruamel.yaml-0.18.10-py3-none-any.whl", hash = "sha256:30f22513ab2301b3d2b577adc121c6471f28734d3d9728581245f1e76468b4f1"}, + {file = "ruamel.yaml-0.18.10.tar.gz", hash = "sha256:20c86ab29ac2153f80a428e1254a8adf686d3383df04490514ca3b79a362db58"}, ] [package.dependencies] diff --git a/pytest.ini b/pytest.ini index 3d8cf704..92ad01e1 100644 --- a/pytest.ini +++ b/pytest.ini @@ -3,3 +3,9 @@ norecursedirs = */site-packages testpaths = test asyncio_mode=auto asyncio_default_fixture_loop_scope="function" +# Suppress warnings of level WARNING and below +log_level = WARNING + +# Optionally, you can filter out UserWarnings generated by logging +filterwarnings = + ignore::UserWarning \ No newline at end of file diff --git a/test/DataApiQuery_test.py b/test/DataApiQuery_test.py index 117f1758..737286b3 100644 --- a/test/DataApiQuery_test.py +++ b/test/DataApiQuery_test.py @@ -23,7 +23,7 @@ def test_DataApiQuery_defaults(): assert_equal(query.starttime, expected_start_time) assert_equal(query.endtime, expected_endtime) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) # assumes the env var DATA_HOST is not set @@ -41,7 +41,7 @@ def test_DataApiQuery_starttime_is_none(): assert_equal(query.starttime, expected_start_time) assert_equal(query.endtime, expected_endtime) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) # assumes the env var DATA_HOST is not set @@ -100,7 +100,7 @@ def test_DataApiQuery_default_endtime(): # endtime is 1 day after start time assert_equal(query.endtime, UTCDateTime("2024-11-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) assert_equal(query.data_host, DataHost.DEFAULT) @@ -122,7 +122,7 @@ def test_DataApiQuery_default_only_endtime(): assert_equal(query.endtime, hour_later) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) assert_equal(query.data_host, DataHost.DEFAULT) diff --git a/test/FilterApiQuery_test.py b/test/FilterApiQuery_test.py index 6393297a..6f734f13 100644 --- a/test/FilterApiQuery_test.py +++ b/test/FilterApiQuery_test.py @@ -23,7 +23,7 @@ def test_FilterApiQuery_defaults(): assert_equal(query.endtime, expected_endtime) assert_equal(query.elements, ["X", "Y", "Z", "F"]) assert_equal(query.input_sampling_period, None) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) assert_equal(query.data_host, DataHost.DEFAULT) @@ -83,7 +83,7 @@ def test_FilterApiQuery_default_endtime(): # endtime is 1 day after start time assert_equal(query.endtime, UTCDateTime("2024-11-02T00:00:00.999")) assert_equal(query.elements, ["X", "Y", "Z", "F"]) - assert_equal(query.sampling_period, SamplingPeriod.MINUTE) + assert_equal(query.sampling_period, None) assert_equal(query.data_type, DataType.VARIATION) assert_equal(query.format, OutputFormat.IAGA2002) assert_equal(query.data_host, DataHost.DEFAULT) @@ -190,3 +190,13 @@ def test_FilterApiQuery_extra_fields(): assert "Extra inputs are not permitted" == err[0]["msg"] assert_equal(query, None) + + +def test_FilterApiQuery_no_output_sampling_period(): + query = None + try: + query = FilterApiQuery(id="ANMO", sampling_period=None) + except Exception as e: + err = e.errors() + assert "Output sampling period cannot be None." == err[0]["msg"] + assert_equal(query, None) diff --git a/test/api_test/ws_test/filter_test.py b/test/api_test/ws_test/filter_test.py index aa0a4d8f..67a09a42 100644 --- a/test/api_test/ws_test/filter_test.py +++ b/test/api_test/ws_test/filter_test.py @@ -34,7 +34,7 @@ def test_get_filter_data_query(test_client): assert_equal(query.format, "iaga2002") assert_equal(query.data_type, "variation") assert_equal(query.input_sampling_period, SamplingPeriod.MINUTE) - assert_equal(query.output_sampling_period, SamplingPeriod.HOUR) + assert_equal(query.sampling_period, SamplingPeriod.HOUR) def test_get_filter_data_query_no_starttime(test_client): -- GitLab From 1695ba974a8ebfe1e9c3953d85dd214d044a3147 Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Fri, 10 Jan 2025 14:00:12 -0700 Subject: [PATCH 09/10] Addressed Josh's comments --- geomagio/api/ws/DataApiQuery.py | 1 - geomagio/api/ws/filter.py | 7 ++----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/geomagio/api/ws/DataApiQuery.py b/geomagio/api/ws/DataApiQuery.py index 5dd2102a..9f5217e0 100644 --- a/geomagio/api/ws/DataApiQuery.py +++ b/geomagio/api/ws/DataApiQuery.py @@ -134,7 +134,6 @@ class DataApiQuery(BaseModel): logging.warning( "Sampling period is None. Default value or further processing needed." ) - # self.sampling_period = 0.0 else: samples = int( diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 5d5ae85b..1f288a6e 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -1,9 +1,7 @@ from typing import List, Union, Optional from fastapi import Query -from obspy.clients.fdsn.header import FDSNNoDataException -from obspy import UTCDateTime, Stream, Trace -from ... import TimeseriesFactory, TimeseriesUtility -import math +from obspy import Stream +from ... import TimeseriesUtility import numpy as np from .DataApiQuery import ( DEFAULT_ELEMENTS, @@ -13,7 +11,6 @@ from .DataApiQuery import ( SamplingPeriod, ) from .FilterApiQuery import FilterApiQuery -from ...algorithm.FilterAlgorithm import STEPS from ...algorithm import FilterAlgorithm import logging as logger from .data import get_data_factory -- GitLab From e639ddd2e8b9f4ac9e2829a4286e8a7022b3c5dd Mon Sep 17 00:00:00 2001 From: spencer <swilbur@usgs.gov> Date: Fri, 10 Jan 2025 14:01:33 -0700 Subject: [PATCH 10/10] Ran lint --- geomagio/api/ws/filter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/geomagio/api/ws/filter.py b/geomagio/api/ws/filter.py index 1f288a6e..69516903 100644 --- a/geomagio/api/ws/filter.py +++ b/geomagio/api/ws/filter.py @@ -1,6 +1,6 @@ from typing import List, Union, Optional from fastapi import Query -from obspy import Stream +from obspy import Stream from ... import TimeseriesUtility import numpy as np from .DataApiQuery import ( -- GitLab