From 605c97263110260180e9c8912805da3fe0084bfc Mon Sep 17 00:00:00 2001 From: Eshanta Mishra Date: Thu, 16 Jul 2026 12:22:34 -0700 Subject: [PATCH] Expand test for geoscience libraries --- geolab-base/test_notebook.ipynb | 777 +++++++++++++++++--------------- geolab-base/test_packages.py | 80 +++- 2 files changed, 468 insertions(+), 389 deletions(-) diff --git a/geolab-base/test_notebook.ipynb b/geolab-base/test_notebook.ipynb index fb15dd6..2fe1dec 100644 --- a/geolab-base/test_notebook.ipynb +++ b/geolab-base/test_notebook.ipynb @@ -1,373 +1,410 @@ { - "cells": [ - { - "cell_type": "markdown", - "id": "118af38b", - "metadata": {}, - "source": [ - "# Smoke tests for `geolab-base`\n", - "\n", - "For every package in `environment.yml` (conda + pip): try to import it and\n", - "exercise one minimal API call. CLI-only packages get a `which`/`--version`\n", - "check instead. A failure here means something installed but doesn't load,\n", - "which is usually a sign of an ABI mismatch or a missing system library.\n", - "\n", - "Run all cells. The summary at the bottom lists pass/fail per package." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Setup" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import importlib\n", - "import shutil\n", - "import subprocess\n", - "import sys\n", - "\n", - "RESULTS = []\n", - "\n", - "\n", - "def py(modname, alias=None, smoke=None):\n", - " \"\"\"Import `modname` and optionally run `smoke(mod)` as a sanity check.\"\"\"\n", - " label = alias or modname\n", - " try:\n", - " mod = importlib.import_module(modname)\n", - " if smoke is not None:\n", - " smoke(mod)\n", - " version = getattr(mod, '__version__', '')\n", - " RESULTS.append((label, 'OK', str(version), ''))\n", - " except Exception as exc:\n", - " RESULTS.append((label, 'FAIL', '', f'{type(exc).__name__}: {exc}'))\n", - "\n", - "\n", - "def cli(cmd, version_flag='--version'):\n", - " \"\"\"Verify `cmd` is on $PATH and responds to a version flag.\"\"\"\n", - " path = shutil.which(cmd)\n", - " if not path:\n", - " RESULTS.append((cmd, 'FAIL', '', 'not on $PATH'))\n", - " return\n", - " try:\n", - " r = subprocess.run([cmd, version_flag],\n", - " capture_output=True, text=True, timeout=10)\n", - " line = (r.stdout or r.stderr).strip().splitlines()\n", - " version = line[0] if line else 'on PATH'\n", - " RESULTS.append((cmd, 'OK', version[:80], ''))\n", - " except Exception as exc:\n", - " RESULTS.append((cmd, 'OK', 'on PATH', f'{type(exc).__name__}'))\n", - "\n", - "\n", - "print(f'Python {sys.version}')\n", - "print(f'sys.prefix: {sys.prefix}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Cloud & storage" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "705a7197", - "metadata": {}, - "outputs": [], - "source": [ - "cli('aws')\n", - "py('awswrangler')\n", - "py('boto3', smoke=lambda m: m.client('s3', region_name='us-east-1'))\n", - "py('fsspec', smoke=lambda m: m.filesystem('memory'))\n", - "py('obstore')\n", - "py('s3fs', smoke=lambda m: m.S3FileSystem)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Geospatial" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "84bab05a", - "metadata": {}, - "outputs": [], - "source": [ - "py('cartopy.crs', alias='cartopy',\n", - " smoke=lambda m: m.PlateCarree())\n", - "py('contextily')\n", - "py('fiona', smoke=lambda m: m.supported_drivers)\n", - "py('folium',\n", - " smoke=lambda m: m.Map(location=[0, 0], zoom_start=2))\n", - "py('osgeo.gdal', alias='gdal',\n", - " smoke=lambda m: m.VersionInfo('RELEASE_NAME'))\n", - "py('ipyleaflet', smoke=lambda m: m.Map())\n", - "py('lonboard')\n", - "py('pyproj', smoke=lambda m: m.CRS('EPSG:4326'))\n", - "py('shapely.geometry', alias='shapely',\n", - " smoke=lambda m: m.Point(0, 0).buffer(1).area)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Core scientific stack" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b383bbe0", - "metadata": {}, - "outputs": [], - "source": [ - "py('numpy', smoke=lambda m: int(m.array([1, 2, 3]).sum()))\n", - "py('numba', smoke=lambda m: m.njit(lambda x: x + 1)(1))\n", - "py('scipy.stats', alias='scipy', smoke=lambda m: m.norm.cdf(0))\n", - "py('pandas',\n", - " smoke=lambda m: m.DataFrame({'a': [1, 2]}).shape)\n", - "py('geopandas')\n", - "import matplotlib; matplotlib.use('Agg')\n", - "py('matplotlib', alias='matplotlib-base',\n", - " smoke=lambda m: m.figure.Figure())\n", - "py('xarray',\n", - " smoke=lambda m: m.DataArray([1, 2, 3]).sum().item())\n", - "py('netCDF4', alias='netcdf4')\n", - "py('h5py')\n", - "py('h5netcdf')\n", - "py('pyarrow',\n", - " smoke=lambda m: m.array([1, 2, 3]).to_pylist())\n", - "py('zarr',\n", - " smoke=lambda m: m.zeros((3,), chunks=3, dtype='f4'))\n", - "py('virtualizarr')\n", - "py('bottleneck',\n", - " smoke=lambda m: m.nansum([1.0, 2.0, float('nan'), 3.0]))\n", - "py('flox')\n", - "py('pooch')\n", - "py('dask.array', alias='dask',\n", - " smoke=lambda m: m.ones(10, chunks=5).sum().compute())\n", - "py('distributed')\n", - "py('dask_gateway', alias='dask-gateway')\n", - "py('cvxpy', smoke=lambda m: m.Variable(name='x'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Geo / geoscience" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "062000c0", - "metadata": {}, - "outputs": [], - "source": [ - "py('dascore')\n", - "cli('gmt', version_flag='--version')\n", - "py('obspy',\n", - " smoke=lambda m: m.UTCDateTime('2020-01-01').timestamp)\n", - "py('obsplus')\n", - "py('pygmt')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Utilities" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "dc28287d", - "metadata": {}, - "outputs": [], - "source": [ - "py('tqdm',\n", - " smoke=lambda m: list(m.tqdm(range(3), disable=True)))\n", - "py('requests')\n", - "py('yaml', alias='pyyaml',\n", - " smoke=lambda m: m.safe_load('a: 1'))\n", - "cli('gs', version_flag='--version') # ghostscript\n", - "cli('ffmpeg', version_flag='-version')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dev tools" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "cli('gh')\n", - "cli('gh-scoped-creds')\n", - "py('pytest')\n", - "cli('ruff')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Jupyter stack & extensions" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6ed8a837", - "metadata": {}, - "outputs": [], - "source": [ - "py('jupyterhub')\n", - "py('jupyter_server')\n", - "py('jupyterlab')\n", - "py('ipykernel')\n", - "py('jupyter_resource_usage', alias='jupyter-resource-usage')\n", - "py('jupyter_ruff', alias='jupyter-ruff')\n", - "py('jupyter_server_proxy', alias='jupyter-server-proxy')\n", - "py('jupyterlab_git', alias='jupyterlab-git')\n", - "py('jupyterlab_myst', alias='jupyterlab-myst')\n", - "py('jupyterlab_code_formatter')\n", - "py('jupyterlab_pygments')\n", - "py('nbdime')" - ] - }, - { - "cell_type": "markdown", - "id": "7788e14a", - "metadata": {}, - "source": [ - "## pip packages & visualization" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "824b272d", - "metadata": {}, - "outputs": [], - "source": [ - "# EarthScope --------------------------------------------------\n", - "py('earthscope_sdk', alias='earthscope-sdk')\n", - "cli('es') # earthscope-cli entry point\n", - "py('earthscopestraintools')\n", - "\n", - "# Jupyter add-ons ---------------------------------------------\n", - "py('jupyterlab_jupyterbook_navigation')\n", - "\n", - "# Visualization & data frames ---------------------------------\n", - "py('altair',\n", - " smoke=lambda m: m.Chart())\n", - "py('plotly')\n", - "py('polars',\n", - " smoke=lambda m: m.DataFrame({'a': [1, 2]}))\n", - "py('vegafusion')\n", - "py('vl_convert', alias='vl-convert-python')\n", - "py('ipympl')\n", - "py('hvplot')\n", - "py('holoviews', alias='holoviews',\n", - " smoke=lambda m: m.Curve([1, 2, 3]))\n", - "py('panel')" - ] - }, - { - "cell_type": "markdown", - "id": "5411c0ef", - "metadata": {}, - "source": [ - "## Interactive widgets" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d7ba172f", - "metadata": {}, - "outputs": [], - "source": [ - "py('ipywidgets',\n", - " smoke=lambda m: m.IntSlider(value=5, min=0, max=10))\n", - "py('anywidget')\n", - "py('bqplot')\n", - "py('ipytree', smoke=lambda m: m.Node(name='root'))\n", - "py('itables')\n", - "py('ipydatagrid')\n", - "from sidecar import Sidecar # noqa: F401\n", - "py('sidecar')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import pandas as pd\n", - "from IPython.display import display\n", - "\n", - "df = pd.DataFrame(RESULTS,\n", - " columns=['package', 'status', 'version', 'error'])\n", - "\n", - "passed = int((df['status'] == 'OK').sum())\n", - "total = len(df)\n", - "failed = total - passed\n", - "\n", - "print(f'Results: {passed}/{total} OK, {failed} failed')\n", - "if failed:\n", - " print('\\nFailures:')\n", - " for _, row in df[df['status'] == 'FAIL'].iterrows():\n", - " print(f\" {row['package']:35s} {row['error']}\")\n", - "\n", - "df.style.map(\n", - " lambda v: ('color: red; font-weight: bold' if v == 'FAIL'\n", - " else 'color: green'),\n", - " subset=['status']\n", - ")" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "name": "python", - "pygments_lexer": "ipython3" - } + "cells": [ + { + "cell_type": "markdown", + "id": "118af38b", + "metadata": {}, + "source": [ + "# Smoke tests for `geolab-base`\n", + "\n", + "For every package in `environment.yml` (conda + pip): try to import it and\n", + "exercise one minimal API call. CLI-only packages get a `which`/`--version`\n", + "check instead. A failure here means something installed but doesn't load,\n", + "which is usually a sign of an ABI mismatch or a missing system library.\n", + "\n", + "Run all cells. The summary at the bottom lists pass/fail per package." + ] }, - "nbformat": 4, - "nbformat_minor": 5 + { + "cell_type": "markdown", + "id": "02bb7947", + "metadata": {}, + "source": [ + "## Setup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28f634c2", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib\n", + "import shutil\n", + "import subprocess\n", + "import sys\n", + "\n", + "RESULTS = []\n", + "\n", + "\n", + "def py(modname, alias=None, smoke=None):\n", + " \"\"\"Import `modname` and optionally run `smoke(mod)` as a sanity check.\"\"\"\n", + " label = alias or modname\n", + " try:\n", + " mod = importlib.import_module(modname)\n", + " if smoke is not None:\n", + " smoke(mod)\n", + " version = getattr(mod, '__version__', '')\n", + " RESULTS.append((label, 'OK', str(version), ''))\n", + " except Exception as exc:\n", + " RESULTS.append((label, 'FAIL', '', f'{type(exc).__name__}: {exc}'))\n", + "\n", + "\n", + "def cli(cmd, version_flag='--version'):\n", + " \"\"\"Verify `cmd` is on $PATH and responds to a version flag.\"\"\"\n", + " path = shutil.which(cmd)\n", + " if not path:\n", + " RESULTS.append((cmd, 'FAIL', '', 'not on $PATH'))\n", + " return\n", + " try:\n", + " r = subprocess.run([cmd, version_flag],\n", + " capture_output=True, text=True, timeout=10)\n", + " line = (r.stdout or r.stderr).strip().splitlines()\n", + " version = line[0] if line else 'on PATH'\n", + " RESULTS.append((cmd, 'OK', version[:80], ''))\n", + " except Exception as exc:\n", + " RESULTS.append((cmd, 'OK', 'on PATH', f'{type(exc).__name__}'))\n", + "\n", + "\n", + "print(f'Python {sys.version}')\n", + "print(f'sys.prefix: {sys.prefix}')" + ] + }, + { + "cell_type": "markdown", + "id": "3633c846", + "metadata": {}, + "source": [ + "## Cloud & storage" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "705a7197", + "metadata": {}, + "outputs": [], + "source": [ + "cli('aws')\n", + "py('awswrangler')\n", + "py('boto3', smoke=lambda m: m.client('s3', region_name='us-east-1'))\n", + "py('fsspec', smoke=lambda m: m.filesystem('memory'))\n", + "py('obstore')\n", + "py('s3fs', smoke=lambda m: m.S3FileSystem)" + ] + }, + { + "cell_type": "markdown", + "id": "482da560", + "metadata": {}, + "source": [ + "## Geospatial" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "84bab05a", + "metadata": {}, + "outputs": [], + "source": [ + "py('cartopy.crs', alias='cartopy',\n", + " smoke=lambda m: m.PlateCarree())\n", + "py('contextily')\n", + "py('fiona', smoke=lambda m: m.supported_drivers)\n", + "py('folium',\n", + " smoke=lambda m: m.Map(location=[0, 0], zoom_start=2))\n", + "py('osgeo.gdal', alias='gdal',\n", + " smoke=lambda m: m.VersionInfo('RELEASE_NAME'))\n", + "py('ipyleaflet', smoke=lambda m: m.Map())\n", + "py('lonboard')\n", + "py('pyproj', smoke=lambda m: m.CRS('EPSG:4326'))\n", + "py('shapely.geometry', alias='shapely',\n", + " smoke=lambda m: m.Point(0, 0).buffer(1).area)" + ] + }, + { + "cell_type": "markdown", + "id": "65195e4e", + "metadata": {}, + "source": [ + "## Core scientific stack" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b383bbe0", + "metadata": {}, + "outputs": [], + "source": [ + "py('numpy', smoke=lambda m: int(m.array([1, 2, 3]).sum()))\n", + "py('numba', smoke=lambda m: m.njit(lambda x: x + 1)(1))\n", + "py('scipy.stats', alias='scipy', smoke=lambda m: m.norm.cdf(0))\n", + "py('pandas',\n", + " smoke=lambda m: m.DataFrame({'a': [1, 2]}).shape)\n", + "py('geopandas')\n", + "import matplotlib; matplotlib.use('Agg')\n", + "py('matplotlib', alias='matplotlib-base',\n", + " smoke=lambda m: m.figure.Figure())\n", + "py('xarray',\n", + " smoke=lambda m: m.DataArray([1, 2, 3]).sum().item())\n", + "py('netCDF4', alias='netcdf4')\n", + "py('h5py')\n", + "py('h5netcdf')\n", + "py('pyarrow',\n", + " smoke=lambda m: m.array([1, 2, 3]).to_pylist())\n", + "py('zarr',\n", + " smoke=lambda m: m.zeros((3,), chunks=3, dtype='f4'))\n", + "py('virtualizarr')\n", + "py('bottleneck',\n", + " smoke=lambda m: m.nansum([1.0, 2.0, float('nan'), 3.0]))\n", + "py('flox')\n", + "py('pooch')\n", + "py('dask.array', alias='dask',\n", + " smoke=lambda m: m.ones(10, chunks=5).sum().compute())\n", + "py('distributed')\n", + "py('dask_gateway', alias='dask-gateway')\n", + "py('cvxpy', smoke=lambda m: m.Variable(name='x'))" + ] + }, + { + "cell_type": "markdown", + "id": "94c73a71", + "metadata": {}, + "source": [ + "## Geo / geoscience" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "062000c0", + "metadata": {}, + "outputs": [], + "source": [ + "py('dascore',\n", + " smoke=lambda m: m.get_example_patch('random_das').decimate(time=8))\n", + "cli('gmt', version_flag='--version')\n", + "py('obspy',\n", + " smoke=lambda m: m.read().filter('bandpass', freqmin=1.0, freqmax=10.0))\n", + "py('pygmt',\n", + " smoke=lambda m: m.Figure().coast(\n", + " region=[-10, 10, -10, 10], projection='M6c',land='gray', water='lightblue', shorelines='1/0.5p', borders='1/0.5p')\n", + " )\n", + "\n", + "# obsplus needs a real directory to index, so this check uses a named helper (temp dir → write → WaveBank) instead of a one-line lambda.\n", + "def _obsplus_smoke(m):\n", + " import obspy, os, tempfile\n", + " stream = obspy.read()\n", + " d = tempfile.mkdtemp()\n", + " stream.write(os.path.join(d, \"example.mseed\"), format=\"MSEED\")\n", + " bank = m.WaveBank(d)\n", + " bank.update_index()\n", + " assert len(bank.read_index()) > 0\n", + " got = bank.get_waveforms()\n", + " assert {tr.id for tr in got} == {tr.id for tr in stream}\n", + "\n", + "py('obsplus', smoke=_obsplus_smoke)" + ] + }, + { + "cell_type": "markdown", + "id": "6ae8ebd8", + "metadata": {}, + "source": [ + "## Utilities" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "dc28287d", + "metadata": {}, + "outputs": [], + "source": [ + "py('tqdm',\n", + " smoke=lambda m: list(m.tqdm(range(3), disable=True)))\n", + "py('requests')\n", + "py('yaml', alias='pyyaml',\n", + " smoke=lambda m: m.safe_load('a: 1'))\n", + "cli('gs', version_flag='--version') # ghostscript\n", + "cli('ffmpeg', version_flag='-version')" + ] + }, + { + "cell_type": "markdown", + "id": "a3611a30", + "metadata": {}, + "source": [ + "## Dev tools" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "1ec00cc8", + "metadata": {}, + "outputs": [], + "source": [ + "cli('gh')\n", + "cli('gh-scoped-creds')\n", + "py('pytest')\n", + "cli('ruff')" + ] + }, + { + "cell_type": "markdown", + "id": "c45e2fdd", + "metadata": {}, + "source": [ + "## Jupyter stack & extensions" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ed8a837", + "metadata": {}, + "outputs": [], + "source": [ + "py('jupyterhub')\n", + "py('jupyter_server')\n", + "py('jupyterlab')\n", + "py('ipykernel')\n", + "py('jupyter_resource_usage', alias='jupyter-resource-usage')\n", + "py('jupyter_ruff', alias='jupyter-ruff')\n", + "py('jupyter_server_proxy', alias='jupyter-server-proxy')\n", + "py('jupyterlab_git', alias='jupyterlab-git')\n", + "py('jupyterlab_myst', alias='jupyterlab-myst')\n", + "py('jupyterlab_code_formatter')\n", + "py('jupyterlab_pygments')\n", + "py('nbdime')" + ] + }, + { + "cell_type": "markdown", + "id": "7788e14a", + "metadata": {}, + "source": [ + "## pip packages & visualization" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "824b272d", + "metadata": {}, + "outputs": [], + "source": [ + "# EarthScope --------------------------------------------------\n", + "py('earthscope_sdk', alias='earthscope-sdk')\n", + "cli('es') # earthscope-cli entry point\n", + "py('earthscopestraintools')\n", + "\n", + "# Jupyter add-ons ---------------------------------------------\n", + "py('jupyterlab_jupyterbook_navigation')\n", + "\n", + "# Visualization & data frames ---------------------------------\n", + "py('altair',\n", + " smoke=lambda m: m.Chart())\n", + "py('plotly')\n", + "py('polars',\n", + " smoke=lambda m: m.DataFrame({'a': [1, 2]}))\n", + "py('vegafusion')\n", + "py('vl_convert', alias='vl-convert-python')\n", + "py('ipympl')\n", + "py('hvplot')\n", + "py('holoviews', alias='holoviews',\n", + " smoke=lambda m: m.Curve([1, 2, 3]))\n", + "py('panel')" + ] + }, + { + "cell_type": "markdown", + "id": "5411c0ef", + "metadata": {}, + "source": [ + "## Interactive widgets" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d7ba172f", + "metadata": {}, + "outputs": [], + "source": [ + "py('ipywidgets',\n", + " smoke=lambda m: m.IntSlider(value=5, min=0, max=10))\n", + "py('anywidget')\n", + "py('bqplot')\n", + "py('ipytree', smoke=lambda m: m.Node(name='root'))\n", + "py('itables')\n", + "py('ipydatagrid')\n", + "from sidecar import Sidecar # noqa: F401\n", + "py('sidecar')" + ] + }, + { + "cell_type": "markdown", + "id": "c4cd9033", + "metadata": {}, + "source": [ + "## Summary" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2ab76f3e", + "metadata": {}, + "outputs": [], + "source": [ + "import pandas as pd\n", + "from IPython.display import display\n", + "\n", + "df = pd.DataFrame(RESULTS,\n", + " columns=['package', 'status', 'version', 'error'])\n", + "\n", + "passed = int((df['status'] == 'OK').sum())\n", + "total = len(df)\n", + "failed = total - passed\n", + "\n", + "print(f'Results: {passed}/{total} OK, {failed} failed')\n", + "if failed:\n", + " print('\\nFailures:')\n", + " for _, row in df[df['status'] == 'FAIL'].iterrows():\n", + " print(f\" {row['package']:35s} {row['error']}\")\n", + "\n", + "df.style.map(\n", + " lambda v: ('color: red; font-weight: bold' if v == 'FAIL'\n", + " else 'color: green'),\n", + " subset=['status']\n", + ")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.12.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 } diff --git a/geolab-base/test_packages.py b/geolab-base/test_packages.py index 5ff25f0..afda1d5 100644 --- a/geolab-base/test_packages.py +++ b/geolab-base/test_packages.py @@ -303,33 +303,75 @@ def test_distributed(): def test_dascore(): - import dascore - - assert hasattr(dascore, "__version__") + import dascore as dc + + patch = dc.get_example_patch("random_das") # synthetic DAS data, no download + + assert "time" in patch.dims + assert "distance" in patch.dims + sizes = dict(zip(patch.dims, patch.data.shape)) + assert sizes["time"] > 0 and sizes["distance"] > 0 + + decimated = patch.decimate(time=8) + dec_sizes = dict(zip(decimated.dims, decimated.data.shape)) + assert dec_sizes["time"] < sizes["time"] # fewer time samples + assert dec_sizes["distance"] == sizes["distance"] # distance unchanged def test_gmt_cli(): - out = _cli_version("gmt") + #engine and map data are tested through test_pygmt + out = _cli_version("gmt") assert re.match(r"\d+\.\d+", out.strip()) # gmt --version prints bare "6.6.0" def test_obspy(): - from obspy import UTCDateTime - - t = UTCDateTime("2020-01-01T12:30:45") - assert t.year == 2020 - assert t.month == 1 - assert t.hour == 12 - - -def test_pygmt(): + import obspy + + st = obspy.read() # bundled 3-trace example seismogram that comes with obspy + + assert len(st) == 3 #checks the stream contains exactly three traces + tr = st[0] + assert tr.stats.sampling_rate > 0 + assert tr.stats.npts == len(tr.data) + # Run a real signal-processing step: a bandpass filter (1–10 Hz). + n_before = tr.stats.npts + st.filter("bandpass", freqmin=1.0, freqmax=10.0) + assert st[0].stats.npts == n_before # filtering preserves sample count + assert st[0].data.shape == (n_before,) # still a populated 1-D waveform + + +def test_pygmt(tmp_path): import pygmt - - assert pygmt.__version__ - - -def test_obsplus(): - import obsplus # noqa: F401 + + fig = pygmt.Figure() + fig.coast( + region=[-10, 10, -10, 10], + projection="M6c", + land="gray", + water="lightblue", + shorelines="1/0.5p", + borders="1/0.5p", + ) + out = tmp_path / "coast.png" + fig.savefig(out) + assert out.exists() + assert out.stat().st_size > 0 + + +def test_obsplus(tmp_path): + import obspy + import obsplus + + # Write the bundled obspy example stream into a temp dir in MSEED format. + stream=obspy.read() + stream.write(str(tmp_path / "example.mseed"), format="MSEED") + + bank = obsplus.WaveBank(str(tmp_path)) #creates wavebank representing the tmp path. + bank.update_index() + + assert len(bank.read_index()) > 0 # index has entries + got = bank.get_waveforms() + assert {tr.id for tr in got} == {tr.id for tr in stream} #checks the channels that come back match the channels that went in # ─── Optimization ─────────────────────────────────────────────