From d4d4e7f2b081608146e487422271286e289ec552 Mon Sep 17 00:00:00 2001 From: Alexandra Hobbs <ahobbs@contractor.usgs.gov> Date: Tue, 3 Dec 2024 15:04:41 -0700 Subject: [PATCH] Update pytest library and add pytest-asyncio and pytest-mock for better testing. Add pytest unitests for all routes in login.py. Fix a bug where an unauthorized request would error and return a 500 instead of a 401. Remove the depcrecated app.on_event functions in favor of lifespan events. --- README.md | 29 +- code.json | 4 +- docs/develop.md | 3 + docs/install.md | 2 +- docs/metadata_webservice.md | 56 +- geomagio/Metadata.py | 1394 ------------------- geomagio/ObservatoryMetadata.py | 96 +- geomagio/api/app.py | 20 +- geomagio/api/secure/login.py | 3 +- geomagio/api/ws/Observatory.py | 6 +- geomagio/metadata/MetadataFactory.py | 10 +- geomagio/metadata/instrument/Instrument.py | 2 +- geomagio/processing/copy_absolutes.py | 2 +- geomagio/processing/copy_instrument.py | 7 +- localdev/local_development.md | 16 +- poetry.lock | 263 ++-- pyproject.toml | 6 +- pytest.ini | 6 +- test/ObservatoryMetadata_test.py | 2 +- test/api_test/secure_test/login_test.py | 268 ++++ test/api_test/ws_test/elements_test.py | 22 + test/api_test/ws_test/observatories_test.py | 41 + test/api_test/ws_test/variometers_test.py | 44 + test/iaga2002_test/IAGA2002Parser_test.py | 2 +- test/imfjson_test/IMFJSONWriter_test.py | 6 +- test/metadata/MetadataFactory_test.py | 31 + 26 files changed, 753 insertions(+), 1588 deletions(-) delete mode 100644 geomagio/Metadata.py create mode 100644 test/api_test/secure_test/login_test.py create mode 100644 test/api_test/ws_test/elements_test.py create mode 100644 test/api_test/ws_test/observatories_test.py create mode 100644 test/api_test/ws_test/variometers_test.py create mode 100644 test/metadata/MetadataFactory_test.py diff --git a/README.md b/README.md index 436c92474..9de81eed3 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,34 @@ output_factory.write_file( ### Docker -Docker is the simplest install option. Find instructions [here](./localdev/local_development.md). +Docker is the simplest install option. + +1. Create and start a new container + + named `geomagio`, + listening on local port `8000`, + from the image `usgs/geomag-algorithms` on docker hub + + ``` + docker run -dit --name geomagio -p 8000:8000 usgs/geomag-algorithms + ``` + +2. Use the running container + +- Run the `geomag.py` command line interface: + + > To work with files outside the container, + > use a volume mount when starting the container + + ``` + docker exec -it geomagio geomag.py + ``` + +- Or, to run an interactive python prompt: + + ``` + docker exec -it geomagio python + ``` ## Algorithms diff --git a/code.json b/code.json index 0715617a1..bb37638f6 100644 --- a/code.json +++ b/code.json @@ -3,7 +3,7 @@ "name": "geomag-algorithms", "organization": "U.S. Geological Survey", "description": "Library for processing Geomagnetic timeseries data.", - "version": "1.11.1", + "version": "1.12.1", "status": "Development", "permissions": { "usageType": "openSource", @@ -35,7 +35,7 @@ "email": "gs-haz_dev_team_group@usgs.gov" }, "date": { - "metadataLastUpdated": "2024-09-27" + "metadataLastUpdated": "2024-12-17" } } ] \ No newline at end of file diff --git a/docs/develop.md b/docs/develop.md index 932d5ed75..b9985919e 100644 --- a/docs/develop.md +++ b/docs/develop.md @@ -111,3 +111,6 @@ https://black.readthedocs.io/en/stable/the_black_code_style Resolve any rebase conflicts. If you have already pushed this branch to your fork, you *may* need to force push because branch history has changed. + +## Local Development +After you get everything installed, you can find further instructions on local development [here](../localdev/local_development.md). diff --git a/docs/install.md b/docs/install.md index 7e5e1fd7c..1bc684aaf 100644 --- a/docs/install.md +++ b/docs/install.md @@ -1,7 +1,7 @@ # Installation This document describes installation instructions for users. For those that wish to modify or develop custom code within **geomag-algorithms**, or prefer to install the Docker container, please see the following documents: > - [Develop](./develop.md) provides installation instruction for developers. -> - [Docker](../localdev/local_development.md) describes Docker container installation and usage. +> - [Docker](./install_docker.md) describes Docker container installation and usage. ## Requirements diff --git a/docs/metadata_webservice.md b/docs/metadata_webservice.md index 23600254e..9c0b5141b 100644 --- a/docs/metadata_webservice.md +++ b/docs/metadata_webservice.md @@ -1,5 +1,41 @@ # Running the Metadata Webservice Locally +## Run mysql in a container (for local development) + +``` +docker run --rm --name mysql-db -e MYSQL_ROOT_PASSWORD=password -p 3306:3306 mysql:5.7 +``` + +This exposes port 3306 so python can connect locally. When running the webservice in a container, container links should be used so the container can access the database container. + +## Set up schema in database + +> This is only needed the first time the database is created. Volume mounts can make this more persistent. + +``` +export DATABASE_URL=mysql://root:password@localhost/geomag_operations +``` + +### Create mysql database +``` +docker exec -it mysql-db mysql -uroot -ppassword +``` +> Inside mysql container: +``` +CREATE DATABASE geomag_operations; +exit +``` + +``` +poetry run python create_db.py +``` + +### Add some testing data (depends on DATABASE_URL environment set above). + +``` +poetry run python test_metadata.py +``` + ## Set up OpenID application in code.usgs.gov. - Under your account, go to settings @@ -16,5 +52,21 @@ Scopes: `openid`, `profile`, `email` -## Running with Docker -[local_development.md](../localdev/local_development.md) describes Docker container installation and usage. +## Start webservice + +- Export variables used for authentication: + +``` +export DATABASE_URL=mysql://root:password@localhost/geomag_operations +export OPENID_CLIENT_ID={Application ID} +export OPENID_CLIENT_SECRET={Secret} +export OPENID_METADATA_URL=https://code.usgs.gov/.well-known/openid-configuration +export SECRET_KEY=changeme +export SECRET_SALT=salt +``` + +- Run app + +``` +poetry run uvicorn geomagio.api:app +``` diff --git a/geomagio/Metadata.py b/geomagio/Metadata.py deleted file mode 100644 index 2ce56f5e6..000000000 --- a/geomagio/Metadata.py +++ /dev/null @@ -1,1394 +0,0 @@ -"""Simulate metadata service until it is implemented. -""" - -from obspy import UTCDateTime - - -def get_instrument(observatory, start_time=None, end_time=None, metadata=None): - """Get instrument metadata - - Args: - observatory: observatory code - start_time: start time to match, or None to match any. - end_time: end time to match, or None to match any. - metadata: use custom list, defaults to _INSTRUMENT_METADATA - Returns: - list of matching metadata - """ - metadata = metadata or _INSTRUMENT_METADATA - return [ - m - for m in metadata - if m["station"] == observatory - and (end_time is None or m["start_time"] is None or m["start_time"] < end_time) - and (start_time is None or m["end_time"] is None or m["end_time"] > start_time) - ] - - -""" -To make this list easier to maintain: - - List NT network stations first, then other networks in alphabetical order - - Within networks, alphabetize by station, then start_time. - - When updating a metadata object, copy/paste the current one to the end of the list and update the endtime appropriately. - - Then update the existing object with the new information. -""" -_INSTRUMENT_METADATA = [ - { - "network": "NT", - "station": "BDT", - "start_time": None, - "end_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 20613, "scale": 966.7624}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 944.1253}], - "W": [{"channel": "W_Volt", "offset": 47450, "scale": 975.5875}], - }, - "electronics": { - "serial": "E574", - # these scale values are calculated manually. - "x-scale": 966.7624, # nT/V - "y-scale": 944.1253, # nT/V - "z-scale": 975.5875, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0449", - # these constants combine with instrument setting for offset - "x-constant": 37027, # nT/mA - "y-constant": 36160, # nT/mA - "z-constant": 37365, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "BDT", - "start_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "end_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 20729.5, "scale": 966.7624}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 944.1253}], - "W": [{"channel": "W_Volt", "offset": 47042.5, "scale": 975.5875}], - }, - "electronics": { - "serial": "E574", - # these scale values are calculated manually. - "x-scale": 966.7624, # nT/V - "y-scale": 944.1253, # nT/V - "z-scale": 975.5875, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0449", - # these constants combine with instrument setting for offset - "x-constant": 37027, # nT/mA - "y-constant": 36160, # nT/mA - "z-constant": 37365, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "BDT", - "start_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 20724.67, "scale": 966.7624}], - "V": [{"channel": "V_Volt", "offset": -13.59, "scale": 944.1253}], - "W": [{"channel": "W_Volt", "offset": 47048.96, "scale": 975.5875}], - }, - "electronics": { - "serial": "E574", - # these scale values are calculated manually. - "x-scale": 966.7624, # nT/V - "y-scale": 944.1253, # nT/V - "z-scale": 975.5875, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0449", - # these constants combine with instrument setting for offset - "x-constant": 37027, # nT/mA - "y-constant": 36160, # nT/mA - "z-constant": 37365, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "BOU", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "BXX", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "BRT", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 506}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 505.6}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 506}, - ], - }, - }, - }, - { - "network": "NT", - "station": "BRW", - "start_time": UTCDateTime("2023-10-24T22:45:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 9214, "scale": 5797.3}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 5777.6}], - "W": [{"channel": "W_Volt", "offset": 37172, "scale": 5895.6}], - }, - "electronics": { - "serial": "????", - # these scale values are calculated manually. - "x-scale": 5797.3, # nT/V - "y-scale": 5777.6, # nT/V - "z-scale": 5895.6, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "????", - # these constants combine with instrument setting for offset - "x-constant": None, # nT/mA - "y-constant": None, # nT/mA - "z-constant": None, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "BSL", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "CMO", - "start_time": UTCDateTime("2023-10-27T16:20:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 12620, "scale": 967.7}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 969.7}], - "W": [{"channel": "W_Volt", "offset": 54907, "scale": 973.4}], - }, - "electronics": { - "serial": "E0568", - # these scale values are used to convert voltage - "x-scale": 967.7, # nT/V - "y-scale": 969.7, # nT/V - "z-scale": 973.4, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0443", - # these constants combine with instrument setting for offset - "x-constant": 37062, # nT/mA - "y-constant": 37141, # nT/mA - "z-constant": 37281, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "CMT", - "start_time": UTCDateTime("2023-10-26T21:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 99.4}, - {"channel": "U_Bin", "offset": 0, "scale": 502.5}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 101.5}, - {"channel": "V_Bin", "offset": 0, "scale": 512.5}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100.98}, - {"channel": "W_Bin", "offset": 0, "scale": 509.15}, - ], - }, - }, - }, - { - "network": "NT", - "station": "DED", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 508.20}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 508.40}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 508.03}, - ], - }, - }, - }, - { - "network": "NT", - "station": "FDT", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "FRD", - "start_time": None, - "end_time": UTCDateTime("2023-08-23T00:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "FRD", - "start_time": UTCDateTime("2023-08-23T00:00:00.000Z"), - "end_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 21639, "scale": 978.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 971.0}], - "W": [{"channel": "W_Volt", "offset": 45573, "scale": 966.7}], - }, - "electronics": { - "serial": "E570", - # these scale values are used to convert voltage - "x-scale": 978.4, # nT/V - "y-scale": 971.0, # nT/V - "z-scale": 966.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0445", - # these constants combine with instrument setting for offset - "x-constant": 37474, # nT/mA - "y-constant": 37191, # nT/mA - "z-constant": 37025, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "FRD", - "start_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "end_time": UTCDateTime("2024-04-04T17:30:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 21639, "scale": 978.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 971.0}], - "W": [{"channel": "W_Volt", "offset": 45573, "scale": 966.7}], - }, - "electronics": { - "serial": "E570", - # these scale values are used to convert voltage - "x-scale": 978.4, # nT/V - "y-scale": 971.0, # nT/V - "z-scale": 966.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0445", - # these constants combine with instrument setting for offset - "x-constant": 37474, # nT/mA - "y-constant": 37191, # nT/mA - "z-constant": 37025, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "FRD", - "start_time": UTCDateTime("2024-04-04T17:30:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 21777, "scale": 978.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 971.0}], - "W": [{"channel": "W_Volt", "offset": 45426, "scale": 966.7}], - }, - "electronics": { - "serial": "E570", - # these scale values are used to convert voltage - "x-scale": 978.4, # nT/V - "y-scale": 971.0, # nT/V - "z-scale": 966.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0445", - # these constants combine with instrument setting for offset - "x-constant": 37474, # nT/mA - "y-constant": 37191, # nT/mA - "z-constant": 37025, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "FRN", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 98.48}, - {"channel": "U_Bin", "offset": 0, "scale": 497.50}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100.60}, - {"channel": "V_Bin", "offset": 0, "scale": 506}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 99}, - {"channel": "W_Bin", "offset": 0, "scale": 501}, - ], - }, - }, - }, - { - "network": "NT", - "station": "GUA", - "start_time": None, - "end_time": UTCDateTime("2024-02-26T03:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "GUA", - "start_time": UTCDateTime("2024-02-26T03:00:00.000Z"), - "end_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 35975, "scale": 314.28}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 310.48}], - "W": [{"channel": "W_Volt", "offset": 7750, "scale": 317.5}], - }, - "electronics": { - "serial": "E0542", - # these scale values are used to convert voltage - "x-scale": 314.28, # V/nT - "y-scale": 310.48, # V/nT - "z-scale": 317.5, # V/nT - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0420", - # these constants combine with instrument setting for offset - "x-constant": 37085, # nT/mA - "y-constant": 36637, # nT/mA - "z-constant": 37465, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "GUA", - "start_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 35976, "scale": 314.28}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 310.48}], - "W": [{"channel": "W_Volt", "offset": 7745, "scale": 317.5}], - }, - "electronics": { - "serial": "E0542", - # these scale values are used to convert voltage - "x-scale": 314.28, # V/nT - "y-scale": 310.48, # V/nT - "z-scale": 317.5, # V/nT - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0420", - # these constants combine with instrument setting for offset - "x-constant": 37085, # nT/mA - "y-constant": 36637, # nT/mA - "z-constant": 37465, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "GUT", - "start_time": None, - "end_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 35989, "scale": 314.28}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 310.48}], - "W": [{"channel": "W_Volt", "offset": 7654, "scale": 317.5}], - }, - "electronics": { - "serial": "E0542", - # these scale values are used to convert voltage - "x-scale": 314.28, # V/nT - "y-scale": 310.48, # V/nT - "z-scale": 317.5, # V/nT - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0420", - # these constants combine with instrument setting for offset - "x-constant": 37085, # nT/mA - "y-constant": 36637, # nT/mA - "z-constant": 37465, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "GUT", - "start_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "end_time": UTCDateTime("2024-02-26T03:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 35975, "scale": 314.28}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 310.48}], - "W": [{"channel": "W_Volt", "offset": 7750, "scale": 317.5}], - }, - "electronics": { - "serial": "E0542", - # these scale values are used to convert voltage - "x-scale": 314.28, # V/nT - "y-scale": 310.48, # V/nT - "z-scale": 317.5, # V/nT - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0420", - # these constants combine with instrument setting for offset - "x-constant": 37085, # nT/mA - "y-constant": 36637, # nT/mA - "z-constant": 37465, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "GUT", - "start_time": UTCDateTime("2024-02-26T03:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "HON", - "start_time": None, - "end_time": UTCDateTime("2024-02-20T20:30:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "HON", - "start_time": UTCDateTime("2024-02-20T20:30:00.000Z"), - "end_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27126, "scale": 315.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 315.0}], - "W": [{"channel": "W_Volt", "offset": 21107.5, "scale": 311.7}], - }, - # this info should get updated when available - "electronics": { - "serial": "E558", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value, and given nT/mA values. - "x-scale": 315.4, # nT/V - "y-scale": 315.0, # nT/V - "z-scale": 311.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0428", - # these constants combine with instrument setting for offset - "x-constant": 37220, # nT/mA - "y-constant": 37175, # nT/mA - "z-constant": 36775, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "HON", - "start_time": UTCDateTime("2024-03-07T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27126, "scale": 315.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 315.0}], - "W": [{"channel": "W_Volt", "offset": 21207.5, "scale": 311.7}], - }, - # this info should get updated when available - "electronics": { - "serial": "E558", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value, and given nT/mA values. - "x-scale": 315.4, # nT/V - "y-scale": 315.0, # nT/V - "z-scale": 311.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0428", - # these constants combine with instrument setting for offset - "x-constant": 37220, # nT/mA - "y-constant": 37175, # nT/mA - "z-constant": 36775, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "HOT", - "start_time": None, - "end_time": UTCDateTime("2022-07-14T16:07:30.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 0, "scale": 971.8}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 970.6}], - "W": [{"channel": "W_Volt", "offset": 0, "scale": 960.2}], - }, - # this info should get updated when available - "electronics": { - "serial": "E558", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value, and given nT/mA values. - "x-scale": 971.8, # nT/V - "y-scale": 970.6, # nT/V - "z-scale": 960.2, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0428", - # these constants combine with instrument setting for offset - "x-constant": 37220, # nT/mA - "y-constant": 37175, # nT/mA - "z-constant": 36775, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "HOT", - "start_time": UTCDateTime("2022-07-14T16:07:30.000Z"), - "end_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27123, "scale": 315.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 315.0}], - "W": [{"channel": "W_Volt", "offset": 21158, "scale": 311.7}], - }, - # this info should get updated when available - "electronics": { - "serial": "E558", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value, and given nT/mA values. - "x-scale": 315.4, # nT/V - "y-scale": 315.0, # nT/V - "z-scale": 311.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0428", - # these constants combine with instrument setting for offset - "x-constant": 37220, # nT/mA - "y-constant": 37175, # nT/mA - "z-constant": 36775, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "HOT", - "start_time": UTCDateTime("2023-09-22T00:00:00.000Z"), - "end_time": UTCDateTime("2024-02-20T20:30:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27126, "scale": 315.4}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 315.0}], - "W": [{"channel": "W_Volt", "offset": 21107.5, "scale": 311.7}], - }, - # this info should get updated when available - "electronics": { - "serial": "E558", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value, and given nT/mA values. - "x-scale": 315.4, # nT/V - "y-scale": 315.0, # nT/V - "z-scale": 311.7, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0428", - # these constants combine with instrument setting for offset - "x-constant": 37220, # nT/mA - "y-constant": 37175, # nT/mA - "z-constant": 36775, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "HOT", - "start_time": UTCDateTime("2024-02-20T20:30:00.000Z"), - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "NEW", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "LLO", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "SHU", - "start_time": None, - "end_time": UTCDateTime("2023-06-28T00:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 505}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 505}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 505}, - ], - }, - }, - }, - { - "network": "NT", - "station": "SHU", - "start_time": UTCDateTime("2023-06-28T00:00:00.000Z"), - "end_time": UTCDateTime("2023-09-07T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 19710, "scale": 944.935}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 964.909}], - "W": [{"channel": "W_Volt", "offset": 48068, "scale": 966.893}], - }, - # this info should get updated when available - "electronics": { - "serial": "E566", - # these scale values are used to convert voltage - # these are calculated using Ohm's law, given scaling resistor value (38.3 kohm), and given nT/mA values. - "x-scale": 944.935, # nT/V - "y-scale": 964.909, # nT/V - "z-scale": 966.893, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0441", - # these constants combine with instrument setting for offset - "x-constant": 36191, # nT/mA - "y-constant": 36956, # nT/mA - "z-constant": 37032, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "SHU", - "start_time": UTCDateTime("2023-09-07T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 19710, "scale": 975.1}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 969.4}], - "W": [{"channel": "W_Volt", "offset": 48068, "scale": 978.5}], - }, - # this info should get updated when available - "electronics": { - "serial": "E0598", - # these scale values are used to convert voltage - "x-scale": 975.1, # nT/V - "y-scale": 969.4, # nT/V - "z-scale": 978.5, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0460", - "x-constant": 37348, # nT/mA - "y-constant": 37127, # nT/mA - "z-constant": 37477, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "SIT", - "start_time": None, - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "SJG", - "start_time": None, - "end_time": UTCDateTime("2023-08-18T19:02:34.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "SJG", - "start_time": UTCDateTime("2023-08-18T19:02:34.000Z"), - "end_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27047, "scale": 313.2034}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.2797}], - "W": [{"channel": "W_Volt", "offset": 24288, "scale": 311.9576}], - }, - "electronics": { - "serial": "E0543", - # these scale values are calculated manually - "x-scale": 313.2034, # nT/V - "y-scale": 312.2797, # nT/V - "z-scale": 311.9576, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0419", - # these constants combine with instrument setting for offset - "x-constant": 36958, # nT/mA - "y-constant": 36849, # nT/mA - "z-constant": 36811, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "SJG", - "start_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 26947.5, "scale": 313.2034}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.2797}], - "W": [{"channel": "W_Volt", "offset": 24690, "scale": 311.9576}], - }, - "electronics": { - "serial": "E0543", - # these scale values are calculated manually - "x-scale": 313.2034, # nT/V - "y-scale": 312.2797, # nT/V - "z-scale": 311.9576, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0419", - # these constants combine with instrument setting for offset - "x-constant": 36958, # nT/mA - "y-constant": 36849, # nT/mA - "z-constant": 36811, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "SJT", - "start_time": None, - "end_time": UTCDateTime("2023-08-18T19:02:34.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 27047, "scale": 313.2034}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 312.2797}], - "W": [{"channel": "W_Volt", "offset": 24288, "scale": 311.9576}], - }, - # this info should get updated when available - "electronics": { - "serial": "E0543", - # these scale values are calculated manually - "x-scale": 313.2034, # nT/V - "y-scale": 312.2797, # nT/V - "z-scale": 311.9576, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0419", - # these constants combine with instrument setting for offset - "x-constant": 36958, # nT/mA - "y-constant": 36849, # nT/mA - "z-constant": 36811, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "SJT", - "start_time": UTCDateTime("2023-08-18T19:02:34.000Z"), - "end_time": None, - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "TUC", - "start_time": None, - "end_time": UTCDateTime("2023-03-29T00:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 500}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 500}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 500}, - ], - }, - }, - }, - { - "network": "NT", - "station": "TUC", - "start_time": UTCDateTime("2023-03-29T00:00:00.000Z"), - "end_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 24024, "scale": 978.355}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 965.901}], - "W": [{"channel": "W_Volt", "offset": 40040, "scale": 954.543}], - }, - # this info should get updated when available - "electronics": { - "serial": "E571", - # these scale values are calculated manually - "x-scale": 978.355, # nT/V - "y-scale": 965.901, # nT/V - "z-scale": 954.543, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0446", - # these constants combine with instrument setting for offset - "x-constant": 37471, # nT/mA - "y-constant": 36994, # nT/mA - "z-constant": 36559, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "TUC", - "start_time": UTCDateTime("2023-08-30T00:00:00.000Z"), - "end_time": None, - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 24016.5, "scale": 978.355}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 965.901}], - "W": [{"channel": "W_Volt", "offset": 39953.5, "scale": 954.543}], - }, - # this info should get updated when available - "electronics": { - "serial": "E571", - # these scale values are calculated manually - "x-scale": 978.355, # nT/V - "y-scale": 965.901, # nT/V - "z-scale": 954.543, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0446", - # these constants combine with instrument setting for offset - "x-constant": 37471, # nT/mA - "y-constant": 36994, # nT/mA - "z-constant": 36559, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "BRW", - "start_time": None, - "end_time": UTCDateTime("2023-10-23T20:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 100}, - {"channel": "U_Bin", "offset": 0, "scale": 506}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 100}, - {"channel": "V_Bin", "offset": 0, "scale": 505.6}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100}, - {"channel": "W_Bin", "offset": 0, "scale": 506}, - ], - }, - }, - }, - { - "network": "NT", - "station": "BRW", - "start_time": UTCDateTime("2023-10-23T19:00:00.000Z"), - "end_time": UTCDateTime("2023-10-24T22:45:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 9217, "scale": 5797.3}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 5777.6}], - "W": [{"channel": "W_Volt", "offset": 56442, "scale": 5895.6}], - }, - "electronics": { - "serial": "????", - # these scale values are calculated manually. - "x-scale": 5797.3, # nT/V - "y-scale": 5777.6, # nT/V - "z-scale": 5895.6, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "????", - # these constants combine with instrument setting for offset - "x-constant": None, # nT/mA - "y-constant": None, # nT/mA - "z-constant": None, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "CMO", - "start_time": None, - "end_time": UTCDateTime("2023-10-26T21:00:00.000Z"), - "instrument": { - "type": "Narod", - "channels": { - "U": [ - {"channel": "U_Volt", "offset": 0, "scale": 99.4}, - {"channel": "U_Bin", "offset": 0, "scale": 502.5}, - ], - "V": [ - {"channel": "V_Volt", "offset": 0, "scale": 101.5}, - {"channel": "V_Bin", "offset": 0, "scale": 512.5}, - ], - "W": [ - {"channel": "W_Volt", "offset": 0, "scale": 100.98}, - {"channel": "W_Bin", "offset": 0, "scale": 509.15}, - ], - }, - }, - }, - { - "network": "NT", - "station": "CMT", - "start_time": None, - "end_time": UTCDateTime("2023-10-26T21:00:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 0, "scale": 967.7}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 969.7}], - "W": [{"channel": "W_Volt", "offset": 0, "scale": 973.4}], - }, - "electronics": { - "serial": "E0568", - # these scale values are used to convert voltage - "x-scale": 967.7, # nT/V - "y-scale": 969.7, # nT/V - "z-scale": 973.4, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0443", - # these constants combine with instrument setting for offset - "x-constant": 37062, # nT/mA - "y-constant": 37141, # nT/mA - "z-constant": 37281, # nT/mA - }, - }, - }, - { - "network": "NT", - "station": "CMO", - "start_time": UTCDateTime("2023-10-26T21:00:00.000Z"), - "end_time": UTCDateTime("2023-10-27T16:20:00.000Z"), - "instrument": { - "type": "FGE", - "channels": { - # each channel maps to a list of components to calculate nT - # TODO: calculate these lists based on "FGE" type - "U": [{"channel": "U_Volt", "offset": 0, "scale": 967.7}], - "V": [{"channel": "V_Volt", "offset": 0, "scale": 969.7}], - "W": [{"channel": "W_Volt", "offset": 0, "scale": 973.4}], - }, - "electronics": { - "serial": "E0568", - # these scale values are used to convert voltage - "x-scale": 967.7, # nT/V - "y-scale": 969.7, # nT/V - "z-scale": 973.4, # nT/V - "temperature-scale": 0.01, # V/K - }, - "sensor": { - "serial": "S0443", - # these constants combine with instrument setting for offset - "x-constant": 37062, # nT/mA - "y-constant": 37141, # nT/mA - "z-constant": 37281, # nT/mA - }, - }, - }, -] diff --git a/geomagio/ObservatoryMetadata.py b/geomagio/ObservatoryMetadata.py index 735a23299..91fcd14cb 100644 --- a/geomagio/ObservatoryMetadata.py +++ b/geomagio/ObservatoryMetadata.py @@ -38,7 +38,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "40.137", "geodetic_longitude": "254.763", "elevation": "1682", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 5527, "is_gin": False, @@ -57,7 +57,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "40.137", "geodetic_longitude": "254.763", "elevation": "1682", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 5527, "is_gin": False, @@ -76,7 +76,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "40.137", "geodetic_longitude": "254.763", "elevation": "1682", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 10000.0, "declination_base": 5527, "is_gin": False, @@ -95,7 +95,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "71.322", "geodetic_longitude": "203.378", "elevation": "10", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 10589, "is_gin": False, @@ -114,7 +114,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "71.322", "geodetic_longitude": "203.378", "elevation": "10", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 10000.0, "declination_base": 10589, "is_gin": False, @@ -133,7 +133,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "30.350", "geodetic_longitude": "270.365", "elevation": "8", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 215772, "is_gin": False, @@ -152,7 +152,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "64.874", "geodetic_longitude": "212.140", "elevation": "197", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 12151, "is_gin": False, @@ -171,7 +171,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "64.874", "geodetic_longitude": "212.140", "elevation": "197", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 10000.0, "declination_base": 12151, "is_gin": False, @@ -190,7 +190,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "70.355", "geodetic_longitude": "211.207", "elevation": "10", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 10755, "is_gin": False, @@ -209,7 +209,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "70.355", "geodetic_longitude": "211.207", "elevation": "10", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 10000.0, "declination_base": 10755, "is_gin": False, @@ -228,7 +228,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "38.205", "geodetic_longitude": "282.627", "elevation": "69", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 209690, "is_gin": False, @@ -247,7 +247,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "38.205", "geodetic_longitude": "282.627", "elevation": "69", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 209690, "is_gin": False, @@ -266,7 +266,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "37.091", "geodetic_longitude": "240.282", "elevation": "331", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 8097, "is_gin": False, @@ -285,7 +285,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "13.588", "geodetic_longitude": "144.867", "elevation": "140", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 764, "is_gin": False, @@ -304,7 +304,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "13.588", "geodetic_longitude": "144.867", "elevation": "140", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 764, "is_gin": False, @@ -323,7 +323,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "21.316", "geodetic_longitude": "202.000", "elevation": "4", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 5982, "is_gin": False, @@ -342,7 +342,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "21.316", "geodetic_longitude": "202.000", "elevation": "4", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 5982, "is_gin": False, @@ -361,8 +361,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "36.232", "geodetic_longitude": "140.186", "elevation": "36", - "sensor_orientation": "HDZF", - "reported": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 0.01, "declination_base": None, "is_gin": False, @@ -381,7 +380,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "48.265", "geodetic_longitude": "242.878", "elevation": "770", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 9547, "is_gin": False, @@ -400,7 +399,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "55.348", "geodetic_longitude": "199.538", "elevation": "80", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 7386, "is_gin": False, @@ -419,7 +418,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "57.058", "geodetic_longitude": "224.675", "elevation": "24", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 12349, "is_gin": False, @@ -438,7 +437,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "18.113", "geodetic_longitude": "293.849", "elevation": "424", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 208439, "is_gin": False, @@ -457,7 +456,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "18.113", "geodetic_longitude": "293.849", "elevation": "424", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 208439, "is_gin": False, @@ -476,7 +475,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "32.174", "geodetic_longitude": "249.267", "elevation": "946", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": 5863, "is_gin": False, @@ -495,7 +494,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "40.137", "geodetic_longitude": "254.764", "elevation": "1682", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -514,8 +513,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "64.300", "geodetic_longitude": "264.000", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -534,8 +532,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "49.600", "geodetic_longitude": "262.900", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -554,8 +551,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "69.200", "geodetic_longitude": "255.000", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -574,8 +570,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "55.300", "geodetic_longitude": "282.300", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -594,8 +589,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "58.800", "geodetic_longitude": "265.900", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -614,8 +608,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "51.000", "geodetic_longitude": "355.500", "elevation": "0", - "sensor_orientation": "HDZF", - "reported": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -634,8 +627,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "-34.400", "geodetic_longitude": "19.200", "elevation": "0", - "sensor_orientation": "HDZF", - "reported": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -654,8 +646,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "63.800", "geodetic_longitude": "291.500", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -674,8 +665,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "54.600", "geodetic_longitude": "246.700", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -694,8 +684,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "45.400", "geodetic_longitude": "284.500", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -714,8 +703,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "74.700", "geodetic_longitude": "265.100", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -734,8 +722,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "62.400", "geodetic_longitude": "245.500", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -754,8 +741,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "47.600", "geodetic_longitude": "307.300", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -774,8 +760,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "48.600", "geodetic_longitude": "236.600", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, @@ -794,8 +779,7 @@ DEFAULT_METADATA = { "geodetic_latitude": "62.400", "geodetic_longitude": "245.500", "elevation": "0", - "sensor_orientation": "XYZF", - "reported": "XYZF", + "sensor_orientation": "XYZ", "sensor_sampling_rate": 100.0, "declination_base": None, "is_gin": False, diff --git a/geomagio/api/app.py b/geomagio/api/app.py index 6cf83e96b..d13f8b92b 100644 --- a/geomagio/api/app.py +++ b/geomagio/api/app.py @@ -10,6 +10,7 @@ and can be run using uvicorn, or any other ASGI server: import logging import os +from contextlib import asynccontextmanager from fastapi import FastAPI from starlette.responses import RedirectResponse @@ -21,19 +22,20 @@ LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") if LOG_BASIC_CONFIG == "true": logging.basicConfig(level=LOG_LEVEL) -app = FastAPI() -app.mount("/ws/secure", secure.app) -app.mount("/ws", ws.app) - -@app.on_event("startup") -async def on_startup(): +@asynccontextmanager +async def lifespan(app: FastAPI): + # on startup await database.connect() + yield + # on shutdown + await database.disconnect() -@app.on_event("shutdown") -async def on_shutdown(): - await database.disconnect() +app = FastAPI(lifespan=lifespan) + +app.mount("/ws/secure", secure.app) +app.mount("/ws", ws.app) @app.get("/", include_in_schema=False) diff --git a/geomagio/api/secure/login.py b/geomagio/api/secure/login.py index 1d0eeff99..e1e57477f 100644 --- a/geomagio/api/secure/login.py +++ b/geomagio/api/secure/login.py @@ -54,7 +54,7 @@ class User(BaseModel): """Information about a logged in user.""" email: str - sub: str # unique outh id + sub: int # unique outh id groups: List[str] = [] name: Optional[str] = None nickname: Optional[str] = None @@ -143,7 +143,6 @@ def require_user( if not user: # not logged in raise HTTPException( - detail=request.url_for("login"), headers={"Cache-Control": "no-cache"}, status_code=401, ) diff --git a/geomagio/api/ws/Observatory.py b/geomagio/api/ws/Observatory.py index 2b1797e00..158e1b4d9 100644 --- a/geomagio/api/ws/Observatory.py +++ b/geomagio/api/ws/Observatory.py @@ -15,6 +15,7 @@ class Observatory(BaseModel): elevation: Optional[int] = None latitude: Optional[float] = None longitude: Optional[float] = None + sensor_sampling_rate: Optional[float] = None # Rather than use validator for populating the agency short name we resorted to using the __init__ function here because the validator mehtod would not overwrite the default None values assigned to agency above. # logic I followed is here https://stackoverflow.com/questions/76286148/how-do-custom-init-functions-work-in-pydantic-with-inheritance @@ -61,7 +62,7 @@ class Observatory(BaseModel): if agency == "GSC": sensor_orientation = "XYZF" else: - sensor_orientation = "HDZF" + sensor_orientation = "HDZ" return sensor_orientation def geojson(self) -> Dict: @@ -73,7 +74,7 @@ class Observatory(BaseModel): "agency": self.agency, "agency_name": self.agency_name, "sensor_orientation": self.sensor_orientation, - "sensor_sampling_rate": 0.01, + "sensor_sampling_rate": self.sensor_sampling_rate, "declination_base": self.declination_base, }, "geometry": ( @@ -103,6 +104,7 @@ for observatory_code, observatory_data in DEFAULT_METADATA.items(): agency_name=metadata["agency_name"], sensor_orientation=metadata["sensor_orientation"], declination_base=metadata.get("declination_base"), + sensor_sampling_rate=metadata["sensor_sampling_rate"], ) OBSERVATORIES.append(observatory) diff --git a/geomagio/metadata/MetadataFactory.py b/geomagio/metadata/MetadataFactory.py index 2ffdeda70..3e3dce3f7 100644 --- a/geomagio/metadata/MetadataFactory.py +++ b/geomagio/metadata/MetadataFactory.py @@ -1,5 +1,6 @@ import os import requests +import datetime from typing import List, Union import json @@ -9,6 +10,9 @@ from pydantic import TypeAdapter from .Metadata import Metadata from .MetadataQuery import MetadataQuery +# Force IPV4 in requests package +requests.packages.urllib3.util.connection.HAS_IPV6 = False + # Set the API host and URL for the Geomagnetic Metadata service GEOMAG_API_HOST = os.getenv("GEOMAG_API_HOST", "geomag.usgs.gov") GEOMAG_API_URL = f"https://{GEOMAG_API_HOST}/ws/secure/metadata" @@ -155,7 +159,7 @@ class MetadataFactory(object): """ response = requests.post( url=self.url, - data=metadata.json(), + data=metadata.model_dump_json(), headers=self._get_headers(), timeout=timeout, ) @@ -183,7 +187,7 @@ class MetadataFactory(object): """ response = requests.put( url=f"{self.url}/{metadata.id}", - data=metadata.json(), + data=metadata.model_dump_json(), headers=self._get_headers(), timeout=timeout, ) @@ -209,7 +213,7 @@ def parse_params(query: MetadataQuery) -> str: for key in query.keys(): element = query[key] # Convert times to ISO format strings - if isinstance(element, UTCDateTime): + if isinstance(element, UTCDateTime) or isinstance(element, datetime.datetime): element = element.isoformat() # Serialize the metadata dictionary to a JSON string elif key == "metadata" and isinstance(element, dict): diff --git a/geomagio/metadata/instrument/Instrument.py b/geomagio/metadata/instrument/Instrument.py index 378ed7da0..4214667e8 100644 --- a/geomagio/metadata/instrument/Instrument.py +++ b/geomagio/metadata/instrument/Instrument.py @@ -1,4 +1,4 @@ -from types import Optional +from typing import Optional from pydantic import BaseModel, Field from enum import Enum diff --git a/geomagio/processing/copy_absolutes.py b/geomagio/processing/copy_absolutes.py index a438c2464..2addce461 100644 --- a/geomagio/processing/copy_absolutes.py +++ b/geomagio/processing/copy_absolutes.py @@ -116,7 +116,7 @@ def create_reading_metadata(reading: Reading, created_by_label: str) -> Metadata category=MetadataCategory.READING, created_by=(created_by_label), endtime=max(measurement_times), - metadata=json.loads(reading.json()), + metadata=json.loads(reading.model_dump_json()), network="NT", starttime=min(measurement_times), station=reading.metadata["station"], diff --git a/geomagio/processing/copy_instrument.py b/geomagio/processing/copy_instrument.py index 32c2c71e7..1e0f0e582 100644 --- a/geomagio/processing/copy_instrument.py +++ b/geomagio/processing/copy_instrument.py @@ -45,7 +45,7 @@ def copy_instrument( show_default="environment variable GITLAB_API_TOKEN", ), metadata_url: str = typer.Option( - default="https://staging-geomag.cr.usgs.gov/ws/secure/metadata", + default="https://geomag.usgs.gov/ws/secure/metadata", help="URL to metadata web service", metavar="URL", ), @@ -129,7 +129,7 @@ def create_metadata( category=MetadataCategory.INSTRUMENT, created_by=created_by_label, endtime=endtime, - metadata=metadata_class(**metadata), + metadata=(metadata_class(**metadata)).model_dump(), network="NT", location="R0", starttime=starttime, @@ -201,8 +201,7 @@ def upload_instrument_metadata( print("Updating metadata") return factory.update_metadata(metadata=instrument) - print("pretending to upload") - # return factory.create_metadata(metadata=instrument) + return factory.create_metadata(metadata=instrument) if __name__ == "__main__": diff --git a/localdev/local_development.md b/localdev/local_development.md index ae659a92f..487984ead 100644 --- a/localdev/local_development.md +++ b/localdev/local_development.md @@ -4,10 +4,18 @@ This docker-compose uses the main Dockerfile to create a `localdev-web-1` container and creates a mysql container called `localdev-database-1` and an edge container called `localdev-edge-1`. ## Prerequisites +1. Download docker without Docker Desktop, at least version 27.0.1. + For mac development: 1. Download colima using homebrew. 2. Start colima and edit virtual machine sizes using `colima start --edit`. Increase the number of CPUs to 16 and the memory to 16. -3. Add the following env vars to your .bashrc or .zshrc or an .env file. See the instructions [here](../docs/metadata_webservice.md) for instructions on creating the OPENID_CLIENT_ID and OPENID_CLIENT_SECRET. The rest of the values can be set to strings of your choice. If you set the values in your .bashrc or .zshrc, run the source command to pick up the new values (ex `source ~/.bashrc`). + +For windows development: +1. Install Docker on WSL2. You can find instructions [here](https://docs.docker.com/engine/install/ubuntu/). + +For both OS: + +Add the following env vars to your .bashrc or .zshrc or an .env file. See the instructions [here](../docs/metadata_webservice.md) for instructions on creating the OPENID_CLIENT_ID and OPENID_CLIENT_SECRET. The rest of the values can be set to strings of your choice. If you set the values in your .bashrc or .zshrc, run the source command to pick up the new values (ex `source ~/.bashrc`). ``` export OPENID_CLIENT_ID="" export OPENID_CLIENT_SECRET="" @@ -17,15 +25,17 @@ export MYSQL_ROOT_PASSWORD="" ``` ## Use -To simply start build and run all the containers, make sure you are in the /localdev directory and run the following command. This includes a reload command for the web container. It will restart the web container when changes are made locally. +To simply build and run all the containers, make sure you are in the /localdev directory and run the following command. This includes a reload command for the web container. It will restart the web container when changes are made locally. ``` docker-compose up ``` +or `docker compose up` if you're not using the docker-compose plugin. If you're not developing locally, use the following command to run the containers in the background. Reload will not work this way. ``` -docker-compmose up -d +docker-compose up -d ``` +or `docker compose up -d` if not using the docker-compose plugin. ## Helpful Docker Commands `docker ps` shows the running containers. diff --git a/poetry.lock b/poetry.lock index 74cc612c8..d2d17532d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -38,13 +38,13 @@ docs = ["sphinx (==7.2.6)", "sphinx-mdinclude (==0.5.3)"] [[package]] name = "alembic" -version = "1.13.3" +version = "1.14.0" description = "A database migration tool for SQLAlchemy." optional = false python-versions = ">=3.8" files = [ - {file = "alembic-1.13.3-py3-none-any.whl", hash = "sha256:908e905976d15235fae59c9ac42c4c5b75cfcefe3d27c0fbf7ae15a37715d80e"}, - {file = "alembic-1.13.3.tar.gz", hash = "sha256:203503117415561e203aa14541740643a611f641517f0209fcae63e9fa09f1a2"}, + {file = "alembic-1.14.0-py3-none-any.whl", hash = "sha256:99bd884ca390466db5e27ffccff1d179ec5c05c965cfefc0607e69f9e411cb25"}, + {file = "alembic-1.14.0.tar.gz", hash = "sha256:b00892b53b3642d0b8dbedba234dbf1924b69be83a9a769d5a624b01094e304b"}, ] [package.dependencies] @@ -656,13 +656,13 @@ files = [ [[package]] name = "dparse" -version = "0.6.3" +version = "0.6.4" description = "A parser for Python dependency files" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "dparse-0.6.3-py3-none-any.whl", hash = "sha256:0d8fe18714056ca632d98b24fbfc4e9791d4e47065285ab486182288813a5318"}, - {file = "dparse-0.6.3.tar.gz", hash = "sha256:27bb8b4bcaefec3997697ba3f6e06b2447200ba273c0b085c3d012a04571b528"}, + {file = "dparse-0.6.4-py3-none-any.whl", hash = "sha256:fbab4d50d54d0e739fbb4dedfc3d92771003a5b9aa8545ca7a7045e3b174af57"}, + {file = "dparse-0.6.4.tar.gz", hash = "sha256:90b29c39e3edc36c6284c82c4132648eaf28a01863eb3c231c2512196132201a"}, ] [package.dependencies] @@ -670,18 +670,20 @@ packaging = "*" tomli = {version = "*", markers = "python_version < \"3.11\""} [package.extras] +all = ["pipenv", "poetry", "pyyaml"] conda = ["pyyaml"] -pipenv = ["pipenv (<=2022.12.19)"] +pipenv = ["pipenv"] +poetry = ["poetry"] [[package]] name = "et-xmlfile" -version = "1.1.0" +version = "2.0.0" description = "An implementation of lxml.xmlfile for the standard library" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "et_xmlfile-1.1.0-py3-none-any.whl", hash = "sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada"}, - {file = "et_xmlfile-1.1.0.tar.gz", hash = "sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c"}, + {file = "et_xmlfile-2.0.0-py3-none-any.whl", hash = "sha256:7a91720bc756843502c3b7504c77b8fe44217c85c537d85037f0f536151b2caa"}, + {file = "et_xmlfile-2.0.0.tar.gz", hash = "sha256:dab3f4764309081ce75662649be815c4c9081e88f0837825f90fd28317d4da54"}, ] [[package]] @@ -700,13 +702,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.115.3" +version = "0.115.6" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.115.3-py3-none-any.whl", hash = "sha256:8035e8f9a2b0aa89cea03b6c77721178ed5358e1aea4cd8570d9466895c0638c"}, - {file = "fastapi-0.115.3.tar.gz", hash = "sha256:c091c6a35599c036d676fa24bd4a6e19fa30058d93d950216cdc672881f6f7db"}, + {file = "fastapi-0.115.6-py3-none-any.whl", hash = "sha256:e9240b29e36fa8f4bb7290316988e90c381e5092e0cbe84e7818cc3713bcf305"}, + {file = "fastapi-0.115.6.tar.gz", hash = "sha256:9ec46f7addc14ea472958a96aae5b5de65f39721a46aaf5705c480d9a8b76654"}, ] [package.dependencies] @@ -720,59 +722,61 @@ standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.5)", "htt [[package]] name = "fonttools" -version = "4.54.1" +version = "4.55.3" description = "Tools to manipulate font files" optional = false python-versions = ">=3.8" files = [ - {file = "fonttools-4.54.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7ed7ee041ff7b34cc62f07545e55e1468808691dddfd315d51dd82a6b37ddef2"}, - {file = "fonttools-4.54.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:41bb0b250c8132b2fcac148e2e9198e62ff06f3cc472065dff839327945c5882"}, - {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7965af9b67dd546e52afcf2e38641b5be956d68c425bef2158e95af11d229f10"}, - {file = "fonttools-4.54.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:278913a168f90d53378c20c23b80f4e599dca62fbffae4cc620c8eed476b723e"}, - {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0e88e3018ac809b9662615072dcd6b84dca4c2d991c6d66e1970a112503bba7e"}, - {file = "fonttools-4.54.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:4aa4817f0031206e637d1e685251ac61be64d1adef111060df84fdcbc6ab6c44"}, - {file = "fonttools-4.54.1-cp310-cp310-win32.whl", hash = "sha256:7e3b7d44e18c085fd8c16dcc6f1ad6c61b71ff463636fcb13df7b1b818bd0c02"}, - {file = "fonttools-4.54.1-cp310-cp310-win_amd64.whl", hash = "sha256:dd9cc95b8d6e27d01e1e1f1fae8559ef3c02c76317da650a19047f249acd519d"}, - {file = "fonttools-4.54.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5419771b64248484299fa77689d4f3aeed643ea6630b2ea750eeab219588ba20"}, - {file = "fonttools-4.54.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:301540e89cf4ce89d462eb23a89464fef50915255ece765d10eee8b2bf9d75b2"}, - {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76ae5091547e74e7efecc3cbf8e75200bc92daaeb88e5433c5e3e95ea8ce5aa7"}, - {file = "fonttools-4.54.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82834962b3d7c5ca98cb56001c33cf20eb110ecf442725dc5fdf36d16ed1ab07"}, - {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d26732ae002cc3d2ecab04897bb02ae3f11f06dd7575d1df46acd2f7c012a8d8"}, - {file = "fonttools-4.54.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:58974b4987b2a71ee08ade1e7f47f410c367cdfc5a94fabd599c88165f56213a"}, - {file = "fonttools-4.54.1-cp311-cp311-win32.whl", hash = "sha256:ab774fa225238986218a463f3fe151e04d8c25d7de09df7f0f5fce27b1243dbc"}, - {file = "fonttools-4.54.1-cp311-cp311-win_amd64.whl", hash = "sha256:07e005dc454eee1cc60105d6a29593459a06321c21897f769a281ff2d08939f6"}, - {file = "fonttools-4.54.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:54471032f7cb5fca694b5f1a0aaeba4af6e10ae989df408e0216f7fd6cdc405d"}, - {file = "fonttools-4.54.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8fa92cb248e573daab8d032919623cc309c005086d743afb014c836636166f08"}, - {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a911591200114969befa7f2cb74ac148bce5a91df5645443371aba6d222e263"}, - {file = "fonttools-4.54.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93d458c8a6a354dc8b48fc78d66d2a8a90b941f7fec30e94c7ad9982b1fa6bab"}, - {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5eb2474a7c5be8a5331146758debb2669bf5635c021aee00fd7c353558fc659d"}, - {file = "fonttools-4.54.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9c563351ddc230725c4bdf7d9e1e92cbe6ae8553942bd1fb2b2ff0884e8b714"}, - {file = "fonttools-4.54.1-cp312-cp312-win32.whl", hash = "sha256:fdb062893fd6d47b527d39346e0c5578b7957dcea6d6a3b6794569370013d9ac"}, - {file = "fonttools-4.54.1-cp312-cp312-win_amd64.whl", hash = "sha256:e4564cf40cebcb53f3dc825e85910bf54835e8a8b6880d59e5159f0f325e637e"}, - {file = "fonttools-4.54.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6e37561751b017cf5c40fce0d90fd9e8274716de327ec4ffb0df957160be3bff"}, - {file = "fonttools-4.54.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:357cacb988a18aace66e5e55fe1247f2ee706e01debc4b1a20d77400354cddeb"}, - {file = "fonttools-4.54.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8e953cc0bddc2beaf3a3c3b5dd9ab7554677da72dfaf46951e193c9653e515a"}, - {file = "fonttools-4.54.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:58d29b9a294573d8319f16f2f79e42428ba9b6480442fa1836e4eb89c4d9d61c"}, - {file = "fonttools-4.54.1-cp313-cp313-win32.whl", hash = "sha256:9ef1b167e22709b46bf8168368b7b5d3efeaaa746c6d39661c1b4405b6352e58"}, - {file = "fonttools-4.54.1-cp313-cp313-win_amd64.whl", hash = "sha256:262705b1663f18c04250bd1242b0515d3bbae177bee7752be67c979b7d47f43d"}, - {file = "fonttools-4.54.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:ed2f80ca07025551636c555dec2b755dd005e2ea8fbeb99fc5cdff319b70b23b"}, - {file = "fonttools-4.54.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9dc080e5a1c3b2656caff2ac2633d009b3a9ff7b5e93d0452f40cd76d3da3b3c"}, - {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d152d1be65652fc65e695e5619e0aa0982295a95a9b29b52b85775243c06556"}, - {file = "fonttools-4.54.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8583e563df41fdecef31b793b4dd3af8a9caa03397be648945ad32717a92885b"}, - {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0d1d353ef198c422515a3e974a1e8d5b304cd54a4c2eebcae708e37cd9eeffb1"}, - {file = "fonttools-4.54.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:fda582236fee135d4daeca056c8c88ec5f6f6d88a004a79b84a02547c8f57386"}, - {file = "fonttools-4.54.1-cp38-cp38-win32.whl", hash = "sha256:e7d82b9e56716ed32574ee106cabca80992e6bbdcf25a88d97d21f73a0aae664"}, - {file = "fonttools-4.54.1-cp38-cp38-win_amd64.whl", hash = "sha256:ada215fd079e23e060157aab12eba0d66704316547f334eee9ff26f8c0d7b8ab"}, - {file = "fonttools-4.54.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:f5b8a096e649768c2f4233f947cf9737f8dbf8728b90e2771e2497c6e3d21d13"}, - {file = "fonttools-4.54.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e10d2e0a12e18f4e2dd031e1bf7c3d7017be5c8dbe524d07706179f355c5dac"}, - {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31c32d7d4b0958600eac75eaf524b7b7cb68d3a8c196635252b7a2c30d80e986"}, - {file = "fonttools-4.54.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c39287f5c8f4a0c5a55daf9eaf9ccd223ea59eed3f6d467133cc727d7b943a55"}, - {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a7a310c6e0471602fe3bf8efaf193d396ea561486aeaa7adc1f132e02d30c4b9"}, - {file = "fonttools-4.54.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:d3b659d1029946f4ff9b6183984578041b520ce0f8fb7078bb37ec7445806b33"}, - {file = "fonttools-4.54.1-cp39-cp39-win32.whl", hash = "sha256:e96bc94c8cda58f577277d4a71f51c8e2129b8b36fd05adece6320dd3d57de8a"}, - {file = "fonttools-4.54.1-cp39-cp39-win_amd64.whl", hash = "sha256:e8a4b261c1ef91e7188a30571be6ad98d1c6d9fa2427244c545e2fa0a2494dd7"}, - {file = "fonttools-4.54.1-py3-none-any.whl", hash = "sha256:37cddd62d83dc4f72f7c3f3c2bcf2697e89a30efb152079896544a93907733bd"}, - {file = "fonttools-4.54.1.tar.gz", hash = "sha256:957f669d4922f92c171ba01bef7f29410668db09f6c02111e22b2bce446f3285"}, + {file = "fonttools-4.55.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:1dcc07934a2165ccdc3a5a608db56fb3c24b609658a5b340aee4ecf3ba679dc0"}, + {file = "fonttools-4.55.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f7d66c15ba875432a2d2fb419523f5d3d347f91f48f57b8b08a2dfc3c39b8a3f"}, + {file = "fonttools-4.55.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e4ae3592e62eba83cd2c4ccd9462dcfa603ff78e09110680a5444c6925d841"}, + {file = "fonttools-4.55.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62d65a3022c35e404d19ca14f291c89cc5890032ff04f6c17af0bd1927299674"}, + {file = "fonttools-4.55.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d342e88764fb201286d185093781bf6628bbe380a913c24adf772d901baa8276"}, + {file = "fonttools-4.55.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:dd68c87a2bfe37c5b33bcda0fba39b65a353876d3b9006fde3adae31f97b3ef5"}, + {file = "fonttools-4.55.3-cp310-cp310-win32.whl", hash = "sha256:1bc7ad24ff98846282eef1cbeac05d013c2154f977a79886bb943015d2b1b261"}, + {file = "fonttools-4.55.3-cp310-cp310-win_amd64.whl", hash = "sha256:b54baf65c52952db65df39fcd4820668d0ef4766c0ccdf32879b77f7c804d5c5"}, + {file = "fonttools-4.55.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8c4491699bad88efe95772543cd49870cf756b019ad56294f6498982408ab03e"}, + {file = "fonttools-4.55.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5323a22eabddf4b24f66d26894f1229261021dacd9d29e89f7872dd8c63f0b8b"}, + {file = "fonttools-4.55.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5480673f599ad410695ca2ddef2dfefe9df779a9a5cda89503881e503c9c7d90"}, + {file = "fonttools-4.55.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da9da6d65cd7aa6b0f806556f4985bcbf603bf0c5c590e61b43aa3e5a0f822d0"}, + {file = "fonttools-4.55.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e894b5bd60d9f473bed7a8f506515549cc194de08064d829464088d23097331b"}, + {file = "fonttools-4.55.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aee3b57643827e237ff6ec6d28d9ff9766bd8b21e08cd13bff479e13d4b14765"}, + {file = "fonttools-4.55.3-cp311-cp311-win32.whl", hash = "sha256:eb6ca911c4c17eb51853143624d8dc87cdcdf12a711fc38bf5bd21521e79715f"}, + {file = "fonttools-4.55.3-cp311-cp311-win_amd64.whl", hash = "sha256:6314bf82c54c53c71805318fcf6786d986461622dd926d92a465199ff54b1b72"}, + {file = "fonttools-4.55.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:f9e736f60f4911061235603a6119e72053073a12c6d7904011df2d8fad2c0e35"}, + {file = "fonttools-4.55.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a8aa2c5e5b8b3bcb2e4538d929f6589a5c6bdb84fd16e2ed92649fb5454f11c"}, + {file = "fonttools-4.55.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07f8288aacf0a38d174445fc78377a97fb0b83cfe352a90c9d9c1400571963c7"}, + {file = "fonttools-4.55.3-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8d5e8916c0970fbc0f6f1bece0063363bb5857a7f170121a4493e31c3db3314"}, + {file = "fonttools-4.55.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae3b6600565b2d80b7c05acb8e24d2b26ac407b27a3f2e078229721ba5698427"}, + {file = "fonttools-4.55.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:54153c49913f45065c8d9e6d0c101396725c5621c8aee744719300f79771d75a"}, + {file = "fonttools-4.55.3-cp312-cp312-win32.whl", hash = "sha256:827e95fdbbd3e51f8b459af5ea10ecb4e30af50221ca103bea68218e9615de07"}, + {file = "fonttools-4.55.3-cp312-cp312-win_amd64.whl", hash = "sha256:e6e8766eeeb2de759e862004aa11a9ea3d6f6d5ec710551a88b476192b64fd54"}, + {file = "fonttools-4.55.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a430178ad3e650e695167cb53242dae3477b35c95bef6525b074d87493c4bf29"}, + {file = "fonttools-4.55.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:529cef2ce91dc44f8e407cc567fae6e49a1786f2fefefa73a294704c415322a4"}, + {file = "fonttools-4.55.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e75f12c82127486fac2d8bfbf5bf058202f54bf4f158d367e41647b972342ca"}, + {file = "fonttools-4.55.3-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:859c358ebf41db18fb72342d3080bce67c02b39e86b9fbcf1610cca14984841b"}, + {file = "fonttools-4.55.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:546565028e244a701f73df6d8dd6be489d01617863ec0c6a42fa25bf45d43048"}, + {file = "fonttools-4.55.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:aca318b77f23523309eec4475d1fbbb00a6b133eb766a8bdc401faba91261abe"}, + {file = "fonttools-4.55.3-cp313-cp313-win32.whl", hash = "sha256:8c5ec45428edaa7022f1c949a632a6f298edc7b481312fc7dc258921e9399628"}, + {file = "fonttools-4.55.3-cp313-cp313-win_amd64.whl", hash = "sha256:11e5de1ee0d95af4ae23c1a138b184b7f06e0b6abacabf1d0db41c90b03d834b"}, + {file = "fonttools-4.55.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:caf8230f3e10f8f5d7593eb6d252a37caf58c480b19a17e250a63dad63834cf3"}, + {file = "fonttools-4.55.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b586ab5b15b6097f2fb71cafa3c98edfd0dba1ad8027229e7b1e204a58b0e09d"}, + {file = "fonttools-4.55.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a8c2794ded89399cc2169c4d0bf7941247b8d5932b2659e09834adfbb01589aa"}, + {file = "fonttools-4.55.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cf4fe7c124aa3f4e4c1940880156e13f2f4d98170d35c749e6b4f119a872551e"}, + {file = "fonttools-4.55.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:86721fbc389ef5cc1e2f477019e5069e8e4421e8d9576e9c26f840dbb04678de"}, + {file = "fonttools-4.55.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:89bdc5d88bdeec1b15af790810e267e8332d92561dce4f0748c2b95c9bdf3926"}, + {file = "fonttools-4.55.3-cp38-cp38-win32.whl", hash = "sha256:bc5dbb4685e51235ef487e4bd501ddfc49be5aede5e40f4cefcccabc6e60fb4b"}, + {file = "fonttools-4.55.3-cp38-cp38-win_amd64.whl", hash = "sha256:cd70de1a52a8ee2d1877b6293af8a2484ac82514f10b1c67c1c5762d38073e56"}, + {file = "fonttools-4.55.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:bdcc9f04b36c6c20978d3f060e5323a43f6222accc4e7fcbef3f428e216d96af"}, + {file = "fonttools-4.55.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c3ca99e0d460eff46e033cd3992a969658c3169ffcd533e0a39c63a38beb6831"}, + {file = "fonttools-4.55.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22f38464daa6cdb7b6aebd14ab06609328fe1e9705bb0fcc7d1e69de7109ee02"}, + {file = "fonttools-4.55.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed63959d00b61959b035c7d47f9313c2c1ece090ff63afea702fe86de00dbed4"}, + {file = "fonttools-4.55.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5e8d657cd7326eeaba27de2740e847c6b39dde2f8d7cd7cc56f6aad404ddf0bd"}, + {file = "fonttools-4.55.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fb594b5a99943042c702c550d5494bdd7577f6ef19b0bc73877c948a63184a32"}, + {file = "fonttools-4.55.3-cp39-cp39-win32.whl", hash = "sha256:dc5294a3d5c84226e3dbba1b6f61d7ad813a8c0238fceea4e09aa04848c3d851"}, + {file = "fonttools-4.55.3-cp39-cp39-win_amd64.whl", hash = "sha256:aedbeb1db64496d098e6be92b2e63b5fac4e53b1b92032dfc6988e1ea9134a4d"}, + {file = "fonttools-4.55.3-py3-none-any.whl", hash = "sha256:f412604ccbeee81b091b420272841e5ec5ef68967a9790e80bffd0e30b8e2977"}, + {file = "fonttools-4.55.3.tar.gz", hash = "sha256:3983313c2a04d6cc1fe9251f8fc647754cf49a61dac6cb1e7249ae67afaafc45"}, ] [package.extras] @@ -1369,13 +1373,13 @@ source = ["Cython (>=3.0.11)"] [[package]] name = "mako" -version = "1.3.6" +version = "1.3.8" description = "A super-fast templating language that borrows the best ideas from the existing templating languages." optional = false python-versions = ">=3.8" files = [ - {file = "Mako-1.3.6-py3-none-any.whl", hash = "sha256:a91198468092a2f1a0de86ca92690fb0cfc43ca90ee17e15d93662b4c04b241a"}, - {file = "mako-1.3.6.tar.gz", hash = "sha256:9ec3a1583713479fae654f83ed9fa8c9a4c16b7bb0daba0e6bbebff50c0d983d"}, + {file = "Mako-1.3.8-py3-none-any.whl", hash = "sha256:42f48953c7eb91332040ff567eb7eea69b22e7a4affbc5ba8e845e8f730f6627"}, + {file = "mako-1.3.8.tar.gz", hash = "sha256:577b97e414580d3e088d47c2dbbe9594aa7a5146ed2875d4dfa9075af2dd3cc8"}, ] [package.dependencies] @@ -1688,13 +1692,13 @@ typing-extensions = ">=3.7.4" [[package]] name = "packaging" -version = "24.1" +version = "24.2" description = "Core utilities for Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, - {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -2073,13 +2077,13 @@ diagrams = ["jinja2", "railroad-diagrams"] [[package]] name = "pytest" -version = "7.4.4" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -2087,11 +2091,29 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" -tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.24.0" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"}, + {file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"}, +] + +[package.dependencies] +pytest = ">=8.2,<9" [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pytest-cov" @@ -2111,6 +2133,23 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + [[package]] name = "python-dateutil" version = "2.9.0.post0" @@ -2379,33 +2418,33 @@ test = ["asv", "gmpy2", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeo [[package]] name = "setuptools" -version = "75.2.0" +version = "75.3.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-75.2.0-py3-none-any.whl", hash = "sha256:a7fcb66f68b4d9e8e66b42f9876150a3371558f98fa32222ffaa5bced76406f8"}, - {file = "setuptools-75.2.0.tar.gz", hash = "sha256:753bb6ebf1f465a1912e19ed1d41f403a79173a9acf66a42e7e6aec45c3c16ec"}, + {file = "setuptools-75.3.0-py3-none-any.whl", hash = "sha256:f2504966861356aa38616760c0f66568e535562374995367b4e69c7143cf6bcd"}, + {file = "setuptools-75.3.0.tar.gz", hash = "sha256:fba5dd4d766e97be1b1681d98712680ae8f2f26d7881245f2ce9e40714f1a686"}, ] [package.extras] check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)", "ruff (>=0.5.2)"] -core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=2.6.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] +core = ["importlib-metadata (>=6)", "importlib-resources (>=5.10.2)", "jaraco.collections", "jaraco.functools", "jaraco.text (>=3.7)", "more-itertools", "more-itertools (>=8.8)", "packaging", "packaging (>=24)", "platformdirs (>=4.2.2)", "tomli (>=2.0.1)", "wheel (>=0.43.0)"] cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier", "towncrier (<24.7)"] enabler = ["pytest-enabler (>=2.2)"] -test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] -type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.11.*)", "pytest-mypy"] +test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test (>=5.5)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-home (>=0.5)", "pytest-perf", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel (>=0.44.0)"] +type = ["importlib-metadata (>=7.0.2)", "jaraco.develop (>=7.21)", "mypy (==1.12.*)", "pytest-mypy"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -2525,13 +2564,13 @@ SQLAlchemy = ">=0.9.0" [[package]] name = "starlette" -version = "0.41.0" +version = "0.41.3" description = "The little ASGI library that shines." optional = false python-versions = ">=3.8" files = [ - {file = "starlette-0.41.0-py3-none-any.whl", hash = "sha256:a0193a3c413ebc9c78bff1c3546a45bb8c8bcb4a84cae8747d650a65bd37210a"}, - {file = "starlette-0.41.0.tar.gz", hash = "sha256:39cbd8768b107d68bfe1ff1672b38a2c38b49777de46d2a592841d58e3bf7c2a"}, + {file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"}, + {file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"}, ] [package.dependencies] @@ -2543,13 +2582,43 @@ full = ["httpx (>=0.22.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.7 [[package]] name = "tomli" -version = "2.0.2" +version = "2.2.1" description = "A lil' TOML parser" optional = false python-versions = ">=3.8" files = [ - {file = "tomli-2.0.2-py3-none-any.whl", hash = "sha256:2ebe24485c53d303f690b0ec092806a085f07af5a5aa1464f3931eec36caaa38"}, - {file = "tomli-2.0.2.tar.gz", hash = "sha256:d46d457a85337051c36524bc5349dd91b1877838e2979ac5ced3e710ed8a60ed"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] @@ -2574,13 +2643,13 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=5.2,<6.0)", "isort (>=5.0.6,<6. [[package]] name = "types-python-dateutil" -version = "2.9.0.20241003" +version = "2.9.0.20241206" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.9.0.20241003.tar.gz", hash = "sha256:58cb85449b2a56d6684e41aeefb4c4280631246a0da1a719bdbe6f3fb0317446"}, - {file = "types_python_dateutil-2.9.0.20241003-py3-none-any.whl", hash = "sha256:250e1d8e80e7bbc3a6c99b907762711d1a1cdd00e978ad39cb5940f6f0a87f3d"}, + {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, + {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, ] [[package]] @@ -2916,4 +2985,4 @@ pycurl = ["pycurl"] [metadata] lock-version = "2.0" python-versions = ">=3.8,<3.12" -content-hash = "fd766e42eaeb0d161fb69ba57b8df09adbf265f37bd0f65321bfad3aee9f2130" +content-hash = "5d6aca195743faf8f75339d35cda6989c5cafeaa07beb5c26511411f4dd77236" diff --git a/pyproject.toml b/pyproject.toml index cf5cbc54a..d9ef175b0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,7 @@ packages = [ {include = "geomagio" } ] repository="https://code.usgs.gov/ghsc/geomag/geomag-algorithms" -version = "1.11.1" +version = "1.12.1" [tool.poetry.dependencies] @@ -51,8 +51,10 @@ black = "^24.3.0" isort = "^5.10.1" mypy = "^0.982" poethepoet = "^0.16.4" -pytest = "^7.1.3" +pytest = "^8.3.4" pytest-cov = "^4.0.0" +pytest-asyncio = "^0.24.0" +pytest-mock = "^3.14.0" safety = "^2.2.0" # type hints data-science-types = "^0.2.23" diff --git a/pytest.ini b/pytest.ini index 34aed1adc..3d8cf7040 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,7 +1,5 @@ [pytest] norecursedirs = */site-packages testpaths = test -filterwarnings = - # This happens in many qutebrowser dependencies... - ignore:Using or importing the ABCs from 'collections'.*:DeprecationWarning - ignore:the imp module is deprecated in favour of importlib.*:DeprecationWarning \ No newline at end of file +asyncio_mode=auto +asyncio_default_fixture_loop_scope="function" diff --git a/test/ObservatoryMetadata_test.py b/test/ObservatoryMetadata_test.py index ca3d5ada4..795a0128e 100644 --- a/test/ObservatoryMetadata_test.py +++ b/test/ObservatoryMetadata_test.py @@ -13,7 +13,7 @@ METADATA = { "geodetic_latitude": "-90", "geodetic_longitude": "-180", "elevation": "-1000", - "sensor_orientation": "HDZF", + "sensor_orientation": "HDZ", "sensor_sampling_rate": "0.01 second", "declination_base": 20000, "is_gin": False, diff --git a/test/api_test/secure_test/login_test.py b/test/api_test/secure_test/login_test.py new file mode 100644 index 000000000..6097219b5 --- /dev/null +++ b/test/api_test/secure_test/login_test.py @@ -0,0 +1,268 @@ +import pytest +import httpx +from unittest.mock import ANY +from fastapi.testclient import TestClient +from authlib.integrations.base_client.errors import MismatchingStateError +from requests import Response + +from geomagio.api.secure import app +from geomagio.api.secure.SessionMiddleware import SessionMiddleware +from geomagio.api.secure.login import User + +client = TestClient(app) + + +@pytest.fixture() +def valid_token(): + return { + "access_token": "test_access_token", + "token_type": "Bearer", + "expires_in": 7200, + "refresh_token": "test_refresh_toekn", + "scope": "openid email profile", + "created_at": 1733244369, + "id_token": "test_id_token", + "expires_at": 1733251569, + "userinfo": { + "iss": "http://test_url", + "sub": "1234", + "aud": "test_aud", + "exp": 1733244489, + "iat": 1733244369, + "nonce": "test_nonce", + "auth_time": 1733244368, + "sub_legacy": "test_sub_legacy", + "name": "test_user", + "nickname": "test_user_nickname", + "preferred_username": "test_preferred_username", + "email": "test_email", + "email_verified": True, + "profile": "http://test_url/user", + "picture": "http://picture_url", + "groups_direct": ["group1", "group2"], + }, + } + + +@pytest.fixture() +def valid_userinfo(): + return { + "sub": "1234", + "sub_legacy": "test_sub_legacy", + "name": "test_user", + "nickname": "test_user_nickname", + "preferred_username": "test_preferred_username", + "email": "test_email", + "email_verified": True, + "profile": "http://test_url/user", + "picture": "http://picture_url", + "groups": ["group1", "group2"], + } + + +@pytest.fixture() +def valid_gitlab_user(): + return { + "id": 1234, + "email": "test_email", + "name": "test_user", + "username": "test_user_nickname", + "avatar_url": "http://picture_url", + } + + +@pytest.mark.asyncio +async def test_authorization_valid(valid_token, valid_userinfo, mocker): + + mock_authorize = mocker.AsyncMock(return_value=valid_token) + mocker.patch( + "geomagio.api.secure.login.oauth.openid.authorize_access_token", mock_authorize + ) + + mock_userinfo = mocker.AsyncMock(return_value=valid_userinfo) + mocker.patch("geomagio.api.secure.login.oauth.openid.userinfo", mock_userinfo) + + mock_save_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "save_session", mock_save_session) + + response = client.get("/authorize") + assert response.status_code == 200 + + valid_session = { + "token": valid_token, + "user": valid_userinfo, + } + + # assert the session data is correct + mock_save_session.assert_called_once_with(ANY, valid_session) + + +@pytest.mark.asyncio +async def test_authorization_invalid_authorize_access_token(): + # assert that requests directly to GET /authorize cause an exception + with pytest.raises(MismatchingStateError) as err: + client.get("/authorize") + + assert ( + str(err.value) + == "mismatching_state: CSRF Warning! State not equal in request and response." + ) + + +@pytest.mark.asyncio +async def test_login_redirects(mocker): + mock_save_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "save_session", mock_save_session) + + mock_redirect = mocker.AsyncMock(return_value={"status_code": 302}) + mocker.patch( + "geomagio.api.secure.login.oauth.openid.authorize_redirect", mock_redirect + ) + + header = "https://testserver/ws/secure/metadata/1" + client.get("/login", headers={"Referer": header}) + + # assert oauth is called with the correct redirect url + mock_redirect.assert_called_once_with( + ANY, "https://testserver/ws/secure/authorize", prompt="login" + ) + + # assert session is saved with correct referrer header + mock_save_session.assert_called_once_with(ANY, {"after_authorize_redirect": header}) + + +@pytest.mark.asyncio +async def test_logout(valid_token, valid_userinfo, mocker): + valid_session = {"token": valid_token, "user": valid_userinfo} + mock_get_session = mocker.AsyncMock(return_value=valid_session) + mocker.patch.object(SessionMiddleware, "get_session", mock_get_session) + + mock_delete_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "delete_session", mock_delete_session) + + client.get(url="/logout", headers={"Cookie": "PHPSESSID=valid_session_id"}) + + mock_get_session.assert_called_once_with("valid_session_id") + mock_delete_session.assert_called_once_with("valid_session_id") + + +@pytest.mark.asyncio +async def test_user_with_valid_session(valid_token, valid_userinfo, mocker): + valid_session = {"token": valid_token, "user": valid_userinfo} + mock_get_session = mocker.AsyncMock(return_value=valid_session) + mocker.patch.object(SessionMiddleware, "get_session", mock_get_session) + + mock_save_session = mocker.AsyncMock(return_value=valid_session) + mocker.patch.object(SessionMiddleware, "save_session", mock_save_session) + + response = client.get(url="/user", headers={"Cookie": "PHPSESSID=valid_session_id"}) + + assert response.status_code == 200 + mock_get_session.assert_called_once_with("valid_session_id") + + user = User(**response.json()) + assert user.email == "test_email" + assert user.sub == 1234 + assert user.groups == ["group1", "group2"] + + +@pytest.mark.asyncio +async def test_user_with_no_session_and_valid_token( + valid_token, valid_userinfo, valid_gitlab_user, mocker +): + valid_user_response = httpx.Response(status_code=200, json=valid_gitlab_user) + + valid_groups = [ + { + "id": 1, + "full_path": "group1", + }, + {"id": 2, "full_path": "group2"}, + ] + + valid_groups_response = httpx.Response(status_code=200, json=valid_groups) + + mock_gitlab_request = mocker.AsyncMock( + side_effect=[ + valid_user_response, + valid_groups_response, + httpx.Response(status_code=200, json={}), + ] + ) + mocker.patch("httpx.AsyncClient.get", mock_gitlab_request) + + valid_session = {"token": valid_token, "user": valid_userinfo} + + mock_save_session = mocker.AsyncMock(return_value=valid_session) + mocker.patch.object(SessionMiddleware, "save_session", mock_save_session) + + response = client.get(url="/user", headers={"Authorization": "valid_gitlab_token"}) + + session_user = { + "email": "test_email", + "sub": 1234, + "groups": ["group1", "group2"], + "name": "test_user", + "nickname": "test_user_nickname", + "picture": "http://picture_url", + } + + assert response.status_code == 200 + mock_save_session.assert_called_once_with(ANY, {"user": session_user}) + + user = User(**response.json()) + assert user.email == "test_email" + assert user.sub == 1234 + assert user.groups == ["group1", "group2"] + + +@pytest.mark.asyncio +async def test_user_with_no_session(mocker): + mock_get_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "get_session", mock_get_session) + + # do not pass in cookie + response = client.get(url="/user") + assert response.status_code == 401 + + mock_get_session.assert_not_called() + + +@pytest.mark.asyncio +async def test_user_with_no_session_and_invalid_token(mocker): + mock_get_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "get_session", mock_get_session) + + mock_gitlab_request = mocker.AsyncMock(return_value=None) + mocker.patch("geomagio.api.secure.login.get_gitlab_user", mock_gitlab_request) + + # do not pass in cookie + response = client.get( + url="/user", headers={"Authorization": "invalid_gitlab_token"} + ) + assert response.status_code == 401 + + mock_get_session.assert_not_called() + mock_gitlab_request.assert_called_once_with(token="invalid_gitlab_token") + + +@pytest.mark.asyncio +async def test_user_invalid_session(mocker): + # mock invalid session. this is created when users GET /metadata without logging in + invalid_session = { + "redirect_uri": "redirect_uri", + "nonce": "nonce_str", + "url": "test_url", + } + mock_get_session = mocker.AsyncMock(return_value=invalid_session) + mocker.patch.object(SessionMiddleware, "get_session", mock_get_session) + + mock_save_session = mocker.AsyncMock() + mocker.patch.object(SessionMiddleware, "save_session", mock_save_session) + + response = client.get( + url="/user", headers={"Cookie": "PHPSESSID=invalid_session_id"} + ) + + assert response.status_code == 401 + mock_get_session.assert_called_once_with("invalid_session_id") diff --git a/test/api_test/ws_test/elements_test.py b/test/api_test/ws_test/elements_test.py new file mode 100644 index 000000000..5549fb76f --- /dev/null +++ b/test/api_test/ws_test/elements_test.py @@ -0,0 +1,22 @@ +from fastapi.testclient import TestClient + +from geomagio.api.ws import app + +client = TestClient(app) + + +def test_get_elements(): + response = client.get("/elements/") + + assert response.status_code == 200 + + body = response.json() + assert body["type"] == "FeatureCollection" + + elements = body["features"] + for e in elements: + assert e["type"] == "Feature" + assert e["id"] != None + assert e["properties"]["name"] != None + assert e["properties"]["units"] != None + assert e["geometry"] == None diff --git a/test/api_test/ws_test/observatories_test.py b/test/api_test/ws_test/observatories_test.py new file mode 100644 index 000000000..dbe95cda1 --- /dev/null +++ b/test/api_test/ws_test/observatories_test.py @@ -0,0 +1,41 @@ +from fastapi.testclient import TestClient + +from geomagio.api.ws import app + +client = TestClient(app) + + +def test_get_all_observatories(): + response = client.get("/observatories/") + + assert response.status_code == 200 + body = response.json() + assert body["type"] == "FeatureCollection" + + observatories = body["features"] + for o in observatories: + assert o["type"] == "Feature" + assert o["id"] != None + assert o["properties"]["name"] != None + assert o["properties"]["agency"] != None + assert o["properties"]["agency_name"] != None + assert o["properties"]["sensor_orientation"] != None + assert o["properties"]["sensor_sampling_rate"] != None + + +def test_get_observatory_by_id(): + response = client.get("/observatories/SIT") + + assert response.status_code == 200 + + body = response.json() + assert body["type"] == "Feature" + assert body["id"] == "SIT" + assert body["properties"]["name"] == "Sitka" + assert body["properties"]["agency"] == "USGS" + assert body["properties"]["agency_name"] == "United States Geological Survey (USGS)" + assert body["properties"]["sensor_orientation"] == "HDZ" + assert body["properties"]["sensor_sampling_rate"] == 100.0 + assert body["properties"]["declination_base"] == 12349 + assert body["geometry"]["type"] == "Point" + assert body["geometry"]["coordinates"] == [224.675, 57.058, 24] diff --git a/test/api_test/ws_test/variometers_test.py b/test/api_test/ws_test/variometers_test.py new file mode 100644 index 000000000..c8b90cd90 --- /dev/null +++ b/test/api_test/ws_test/variometers_test.py @@ -0,0 +1,44 @@ +from fastapi.testclient import TestClient + +from geomagio.api.ws import app + +client = TestClient(app) + + +def test_get_all_variometers(): + response = client.get("/variometers/") + + assert response.status_code == 200 + body = response.json() + assert body["type"] == "FeatureCollection" + + variometers = body["features"] + for v in variometers: + assert v["type"] == "Feature" + assert v["id"] != None + assert v["properties"]["name"] != None + assert v["properties"]["agency"] != None + assert v["properties"]["agency_name"] != None + assert v["properties"]["sensor_orientation"] != None + assert v["properties"]["sensor_sampling_rate"] == None + assert v["properties"]["declination_base"] == None + assert v["geometry"]["type"] == "Point" + assert len(v["geometry"]["coordinates"]) > 0 + + +def test_get_variometer_by_id(): + response = client.get("/variometers/DWPF") + + assert response.status_code == 200 + + body = response.json() + assert body["type"] == "Feature" + assert body["id"] == "DWPF" + assert body["properties"]["name"] == "Disney Wilderness Preserve, Florida, USA" + assert body["properties"]["agency"] == "USGS" + assert body["properties"]["agency_name"] == "United States Geological Survey (USGS)" + assert body["properties"]["sensor_orientation"] == "HDZ" + assert body["properties"]["sensor_sampling_rate"] == None + assert body["properties"]["declination_base"] == None + assert body["geometry"]["type"] == "Point" + assert body["geometry"]["coordinates"] == [-81.4327, 28.1103, 30] diff --git a/test/iaga2002_test/IAGA2002Parser_test.py b/test/iaga2002_test/IAGA2002Parser_test.py index 8cfde259f..04ccc9c3a 100644 --- a/test/iaga2002_test/IAGA2002Parser_test.py +++ b/test/iaga2002_test/IAGA2002Parser_test.py @@ -12,7 +12,7 @@ IAGA2002_EXAMPLE = """ Format IAGA-2002 Geodetic Longitude 254.764 | Elevation 1682 | Reported HDZF | - Sensor Orientation HDZF | + Sensor Orientation HDZ | Digital Sampling 0.01 second | Data Interval Type filtered 1-minute (00:15-01:45) | Data Type variation | diff --git a/test/imfjson_test/IMFJSONWriter_test.py b/test/imfjson_test/IMFJSONWriter_test.py index ff8b19d6d..7792ded45 100644 --- a/test/imfjson_test/IMFJSONWriter_test.py +++ b/test/imfjson_test/IMFJSONWriter_test.py @@ -27,8 +27,10 @@ def test_metadata(): assert_equal(metadata["status"], 200) # Test intermagnet parameters intermag = metadata["intermagnet"] - assert_equal(intermag["reported_orientation"], "HDZF") - assert_equal(intermag["sensor_orientation"], "HDZF") + assert_equal(intermag["reported_orientation"], "".join(EXAMPLE_CHANNELS)) + assert intermag[ + "sensor_orientation" + ] # writer does not validate Iaga2002 data, so assert for existence of values instead. assert_equal(intermag["data_type"], "variation") assert_equal(intermag["sampling_period"], 60) assert_equal(intermag["digital_sampling_rate"], 0.01) diff --git a/test/metadata/MetadataFactory_test.py b/test/metadata/MetadataFactory_test.py new file mode 100644 index 000000000..cde42da53 --- /dev/null +++ b/test/metadata/MetadataFactory_test.py @@ -0,0 +1,31 @@ +import datetime +from obspy import UTCDateTime + +from geomagio.metadata import MetadataQuery +from geomagio.metadata.MetadataFactory import parse_params + + +def test_parse_params_with_UTCDateTime(): + query = MetadataQuery( + station="TUC", + starttime=UTCDateTime(2024, 11, 7), + endtime=UTCDateTime(2024, 11, 8), + ) + + params = parse_params(query) + + assert params["starttime"] == "2024-11-07T00:00:00+00:00" + assert params["endtime"] == "2024-11-08T00:00:00+00:00" + + +def test_parse_params_with_datetime(): + query = MetadataQuery( + station="TUC", + starttime=datetime.datetime(2024, 11, 7), + endtime=datetime.datetime(2024, 11, 8), + ) + + params = parse_params(query) + + assert params["starttime"] == "2024-11-07T00:00:00+00:00" + assert params["endtime"] == "2024-11-08T00:00:00+00:00" -- GitLab