From e9a30eb15701c9ca3d4dc3bfea1834a4a86bb7cc Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 14:30:38 -0600 Subject: [PATCH 01/17] Added `esis.flights.f1.data.level_0()` function to load the 2019 Level-0 dataset. --- docs/make.bat | 4 +- esis/__init__.py | 2 + esis/data/__init__.py | 17 +++ esis/data/_level_0/__init__.py | 5 + esis/data/_level_0/_level_0.py | 71 ++++++++++ esis/data/_level_0/_level_0_test.py | 19 +++ esis/flights/f1/data/__init__.py | 2 + esis/flights/f1/data/_level_0/__init__.py | 5 + esis/flights/f1/data/_level_0/_level_0.py | 158 ++++++++++++++++++++++ pyproject.toml | 3 +- 10 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 esis/data/__init__.py create mode 100644 esis/data/_level_0/__init__.py create mode 100644 esis/data/_level_0/_level_0.py create mode 100644 esis/data/_level_0/_level_0_test.py create mode 100644 esis/flights/f1/data/_level_0/__init__.py create mode 100644 esis/flights/f1/data/_level_0/_level_0.py diff --git a/docs/make.bat b/docs/make.bat index 0cef56e4..1332e88f 100644 --- a/docs/make.bat +++ b/docs/make.bat @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b593cd1da19314a43db9a0854f6f92f2c59217571502da3321f9498c02fa16c8 -size 795 +oid sha256:bcf205ef2f3026bb71a0ed44d71afef0519162e1854d66bbb782dc864e3a05d7 +size 803 diff --git a/esis/__init__.py b/esis/__init__.py index 63b2dfeb..671d327d 100644 --- a/esis/__init__.py +++ b/esis/__init__.py @@ -4,10 +4,12 @@ from . import optics from . import nsroc +from . import data from . import flights __all__ = [ "optics", "nsroc", + "data", "flights", ] diff --git a/esis/data/__init__.py b/esis/data/__init__.py new file mode 100644 index 00000000..7c7bd87f --- /dev/null +++ b/esis/data/__init__.py @@ -0,0 +1,17 @@ +""" +Represent and process ESIS observations into spatial-spectral cubes. + +Description of the ESIS Data Levels +=================================== + +Level 0 +------- + + * The raw data gathered by the ESIS instrument, saved as FITS files. + +""" +from ._level_0 import Level_0 + +__all__ = [ + "Level_0", +] diff --git a/esis/data/_level_0/__init__.py b/esis/data/_level_0/__init__.py new file mode 100644 index 00000000..8c1f8546 --- /dev/null +++ b/esis/data/_level_0/__init__.py @@ -0,0 +1,5 @@ +from ._level_0 import Level_0 + +__all__ = [ + "Level_0", +] diff --git a/esis/data/_level_0/_level_0.py b/esis/data/_level_0/_level_0.py new file mode 100644 index 00000000..b2182c5f --- /dev/null +++ b/esis/data/_level_0/_level_0.py @@ -0,0 +1,71 @@ +import numpy as np +from typing_extensions import Self +import dataclasses +import pathlib +import numpy.typing as npt +import named_arrays as na +import msfc_ccd +import esis + +__all__ = [ + "Level_0", +] + + +@dataclasses.dataclass(eq=False, repr=False) +class Level_0( + msfc_ccd.SensorData, +): + """ + Representation of ESIS Level-0 images, the raw images gathered by the + Data Acquisition and Control System (DACS). + """ + + timeline: None | esis.nsroc.Timeline = None + """ + The sequence of NSROC events associated with these images. + """ + + @classmethod + def from_fits( + cls, + path: str | pathlib.Path | na.AbstractScalarArray, + sensor: msfc_ccd.abc.AbstractSensor, + axis_x: str = "detector_x", + axis_y: str = "detector_y", + timeline: None | esis.nsroc.Timeline = None, + ) -> Self: + + self = super().from_fits( + path=path, + sensor=sensor, + axis_x=axis_x, + axis_y=axis_y, + ) + + self.timeline = timeline + + self.inputs + + return self + + @property + def channel(self) -> na.ScalarArray[npt.NDArray[str]]: + """ + The name of each ESIS channel in a human-readable format. + """ + + sn = self.inputs.serial_number + where_1 = sn == "6" + where_2 = sn == "7" + where_3 = sn == "9" + where_4 = sn == "1" + + result = np.empty_like(sn, dtype=object) + + result[where_1] = "Channel 1" + result[where_2] = "Channel 2" + result[where_3] = "Channel 3" + result[where_4] = "Channel 4" + + return result diff --git a/esis/data/_level_0/_level_0_test.py b/esis/data/_level_0/_level_0_test.py new file mode 100644 index 00000000..7148d36d --- /dev/null +++ b/esis/data/_level_0/_level_0_test.py @@ -0,0 +1,19 @@ +import pytest +import msfc_ccd +from msfc_ccd._images._tests.test_sensor_images import AbstractTestAbstractSensorData +import esis + + +@pytest.mark.parametrize( + argnames="a", + argvalues=[ + esis.flights.f1.data.level_0(), + ] +) +class TestLevel_0( + AbstractTestAbstractSensorData, +): + def test_timeline(self, a: esis.data.Level_0): + result = a.timeline + if result is not None: + assert isinstance(result, esis.nsroc.Timeline) diff --git a/esis/flights/f1/data/__init__.py b/esis/flights/f1/data/__init__.py index 19468e3e..9cb2ad40 100644 --- a/esis/flights/f1/data/__init__.py +++ b/esis/flights/f1/data/__init__.py @@ -3,7 +3,9 @@ """ from ._fits import path_fits +from ._level_0 import level_0 __all__ = [ "path_fits", + "level_0", ] diff --git a/esis/flights/f1/data/_level_0/__init__.py b/esis/flights/f1/data/_level_0/__init__.py new file mode 100644 index 00000000..cef2a963 --- /dev/null +++ b/esis/flights/f1/data/_level_0/__init__.py @@ -0,0 +1,5 @@ +from ._level_0 import level_0 + +__all__ = [ + "level_0", +] diff --git a/esis/flights/f1/data/_level_0/_level_0.py b/esis/flights/f1/data/_level_0/_level_0.py new file mode 100644 index 00000000..2199b71d --- /dev/null +++ b/esis/flights/f1/data/_level_0/_level_0.py @@ -0,0 +1,158 @@ +import msfc_ccd +import esis +from ... import nsroc +from .. import path_fits + +__all__ = [ + "level_0", +] + + +def level_0( + axis_time: str = "time", + axis_channel: str = "channel", + axis_x: str = "detector_x", + axis_y: str = "detector_y", +) -> esis.data.Level_0: + """ + All the raw images captured by ESIS during the 2019 flight. + + Parameters + ---------- + axis_time + The name of the logical axis representing time. + axis_channel + The name of the logical axis representing the different ESIS channels. + axis_x + The name of the logical axis representing the detector's long axis. + axis_y + The name of the logical axis representing the detector's short axis. + + Examples + -------- + + Load the Level-0 dataset into a :class:`esis.data.Level_0` instance. + + .. jupyter-execute:: + + import IPython.display + import matplotlib.pyplot as plt + import astropy.visualization + import named_arrays as na + import esis + + # Define the names of the logical axes + # to use for constructing the Level-0 dataset + axis_time = "time" + axis_channel = "channel" + + # Load the Level-0 dataset into memory + level_0 = esis.flights.f1.data.level_0( + axis_time=axis_time, + axis_channel=axis_channel, + ) + + Make a movie of three frames of the Level-0 dataset. + + .. jupyter-execute:: + + # Define a slice of three frames near apogee + index = {axis_time: slice(20, 23)} + + # Create a figure + fig, axs = na.plt.subplots( + axis_rows="rows", + axis_cols="cols", + nrows=level_0.shape[axis_channel] // 2, + ncols=2, + sharex=True, + sharey=True, + constrained_layout=True, + figsize=(10, 5), + ) + + # Reorganize the axes into a flat array + ax = axs.combine_axes(("rows", "cols"), axis_channel) + ax = ax[{axis_channel: slice(None, None, -1)}] + + # Define the colormap + colorizer = plt.Colorizer( + norm=plt.Normalize( + vmin=level_0.outputs.percentile(1).ndarray, + vmax=level_0.outputs.percentile(99).ndarray, + ), + ) + + # Animate the Level-0 dataset frames + ani = na.plt.pcolormovie( + level_0.inputs.time[index].mean(axis_channel), + level_0.inputs.pixel.x, + level_0.inputs.pixel.y, + C=level_0.outputs[index], + axis_time=axis_time, + ax=ax, + kwargs_pcolormesh=dict( + colorizer=colorizer, + ), + ) + + # Create labels for each axis + na.plt.text( + x=0.5, + y=1.01, + s=level_0.channel, + transform=na.plt.transAxes(ax), + ax=ax, + ha="center", + va="bottom", + ) + na.plt.set_aspect("equal", ax=ax) + na.plt.set_xlabel("detector $x$ (pix)", ax=axs[dict(rows=0)]) + na.plt.set_ylabel("detector $y$ (pix)", ax=axs[dict(cols=0)]) + + # Plot the colorbar using the colormap + plt.colorbar( + mappable=plt.cm.ScalarMappable(colorizer=colorizer), + ax=ax.ndarray, + label="signal (DN)" + ) + + # Render the movie as a javascript animation + plt.close(fig) + IPython.display.HTML(ani.to_jshtml()) + + Plot the FPGA temperatures over the flight. + + .. jupyter-execute:: + + # Convert the time array from ISO to a Python :class:`datetime.datetime` + # instance + time = level_0.inputs.time + time = time.replace(ndarray=time.ndarray.datetime) + + # Plot the result as a line plot + with astropy.visualization.quantity_support(): + fig, ax = plt.subplots() + na.plt.plot( + time, + level_0.inputs.temperature_fpga, + axis=axis_time, + ax=ax, + label=level_0.channel, + ) + ax.set_ylabel(f"FPGA temperature ({ax.get_ylabel()})") + ax.legend() + """ + + path = path_fits( + axis_time=axis_time, + axis_channel=axis_channel, + ) + + return esis.data.Level_0.from_fits( + path=path, + sensor=msfc_ccd.TeledyneCCD230(), + axis_x=axis_x, + axis_y=axis_y, + timeline=nsroc.timeline(), + ) diff --git a/pyproject.toml b/pyproject.toml index 2d926024..dde2ceb9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,7 +17,8 @@ dependencies = [ "numpy", "matplotlib", "astropy", - "optika==0.11.0", + "optika==0.12.0", + "msfc-ccd==0.2.0", "aastex==0.3.1", ] dynamic = ["version"] From 7e90656eb9e489dfec1dc60f9dfe9f3f8aa4b507 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 14:44:15 -0600 Subject: [PATCH 02/17] black --- esis/data/_level_0/_level_0_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esis/data/_level_0/_level_0_test.py b/esis/data/_level_0/_level_0_test.py index 7148d36d..82ac5e86 100644 --- a/esis/data/_level_0/_level_0_test.py +++ b/esis/data/_level_0/_level_0_test.py @@ -8,7 +8,7 @@ argnames="a", argvalues=[ esis.flights.f1.data.level_0(), - ] + ], ) class TestLevel_0( AbstractTestAbstractSensorData, From 8df7b98d1aa7c18244ce587fb8ada842fa27d3d2 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 14:46:28 -0600 Subject: [PATCH 03/17] black --- esis/data/__init__.py | 1 + 1 file changed, 1 insertion(+) diff --git a/esis/data/__init__.py b/esis/data/__init__.py index 7c7bd87f..fa62f1d7 100644 --- a/esis/data/__init__.py +++ b/esis/data/__init__.py @@ -10,6 +10,7 @@ * The raw data gathered by the ESIS instrument, saved as FITS files. """ + from ._level_0 import Level_0 __all__ = [ From dfe1a5fb7ec522974b749c4c8901efb642df047b Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 16:40:09 -0600 Subject: [PATCH 04/17] ruff --- esis/data/_level_0/_level_0_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/esis/data/_level_0/_level_0_test.py b/esis/data/_level_0/_level_0_test.py index 82ac5e86..05a91b38 100644 --- a/esis/data/_level_0/_level_0_test.py +++ b/esis/data/_level_0/_level_0_test.py @@ -1,5 +1,4 @@ import pytest -import msfc_ccd from msfc_ccd._images._tests.test_sensor_images import AbstractTestAbstractSensorData import esis From 1e5642edeef2ccb1138d0d7baa2709d83e996595 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 16:40:18 -0600 Subject: [PATCH 05/17] docs --- esis/data/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esis/data/__init__.py b/esis/data/__init__.py index fa62f1d7..f25026f5 100644 --- a/esis/data/__init__.py +++ b/esis/data/__init__.py @@ -7,7 +7,7 @@ Level 0 ------- - * The raw data gathered by the ESIS instrument, saved as FITS files. +* The raw data gathered by the ESIS instrument, saved as FITS files. """ From f9c8b37cb9c6226290e1044335306e8ee99a1189 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 17:16:19 -0600 Subject: [PATCH 06/17] mess with deps --- pyproject.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index dde2ceb9..abb58ae9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,9 +17,9 @@ dependencies = [ "numpy", "matplotlib", "astropy", - "optika==0.12.0", - "msfc-ccd==0.2.0", - "aastex==0.3.1", + "optika>=0.12.0", + "msfc-ccd>=0.2.0", + "aastex>=0.3.1", ] dynamic = ["version"] From 48e66f54c4dbc3f60db5dad4e22f811980ca5313 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 17:25:18 -0600 Subject: [PATCH 07/17] add test paths --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index abb58ae9..2c4e8f69 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -50,6 +50,7 @@ packages = ["esis"] testpaths = [ "esis/optics/_tests", "esis/flights", + "esis/data", "esis/science/papers/instrument/_tests", ] From 286f13d3d37db0ed826b30281c6abffb98bffc4c Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 17:25:31 -0600 Subject: [PATCH 08/17] update codecov action --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3514b950..2246ee27 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -36,10 +36,10 @@ jobs: pip install pytest pytest-cov pytest --cov=. --cov-report=xml --cov-report=html - name: Upload coverage to Codecov - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v5 with: token: ${{ secrets.CODECOV_TOKEN }} - file: coverage.xml + files: coverage.xml flags: unittests env_vars: OS,PYTHON name: codecov-umbrella From 6a5de31a16c55e2f620ca7842cd867b55b6a9f7c Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 17:25:50 -0600 Subject: [PATCH 09/17] update readme badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 39e78d39..456580c8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ESIS -![tests](https://github.com/Kankelborg-Group/ESIS/workflows/tests/badge.svg) +[![tests](https://github.com/Kankelborg-Group/ESIS/actions/workflows/tests.yml/badge.svg)](https://github.com/Kankelborg-Group/ESIS/actions/workflows/tests.yml) [![codecov](https://codecov.io/gh/Kankelborg-Group/ESIS/graph/badge.svg?token=CALT5W6YG3)](https://codecov.io/gh/Kankelborg-Group/ESIS) [![Black](https://github.com/Kankelborg-Group/ESIS/actions/workflows/black.yml/badge.svg)](https://github.com/Kankelborg-Group/ESIS/actions/workflows/black.yml) [![Ruff](https://github.com/Kankelborg-Group/ESIS/actions/workflows/ruff.yml/badge.svg)](https://github.com/Kankelborg-Group/ESIS/actions/workflows/ruff.yml) From cad38b8ac7681409cffd011fb34900448a1acab1 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 21:38:58 -0600 Subject: [PATCH 10/17] bumpy checkout version --- .github/workflows/tests.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 2246ee27..dde395b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -17,11 +17,9 @@ jobs: python-version: ["3.11"] name: ${{ matrix.os }}, Python ${{ matrix.python-version }} tests steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 with: lfs: true - - name: Pull LFS objects - run: git lfs pull - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: From 0b61feea1ee283898e6f24e00268dd75afcd7ce4 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 22:01:48 -0600 Subject: [PATCH 11/17] messing around --- .github/workflows/tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index dde395b4..22ff9e30 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,6 +20,7 @@ jobs: - uses: actions/checkout@v4 with: lfs: true + - run: cat esis/flights/f1/data/_fits/ESIS1_00096.fit.gz - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: From 411cfc9f28d641a01d56410d0c6fa98f3b4ff829 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 22:04:19 -0600 Subject: [PATCH 12/17] more messing around --- .github/workflows/tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 22ff9e30..9258f360 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,7 @@ jobs: - uses: actions/checkout@v4 with: lfs: true - - run: cat esis/flights/f1/data/_fits/ESIS1_00096.fit.gz + - run: ls -l esis/flights/f1/data/_fits/ - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: From 7432ebb9d814be5aafad71f97ebb344d333c2928 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 22:13:16 -0600 Subject: [PATCH 13/17] debugging --- esis/data/_level_0/_level_0.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esis/data/_level_0/_level_0.py b/esis/data/_level_0/_level_0.py index b2182c5f..8984c450 100644 --- a/esis/data/_level_0/_level_0.py +++ b/esis/data/_level_0/_level_0.py @@ -36,6 +36,8 @@ def from_fits( timeline: None | esis.nsroc.Timeline = None, ) -> Self: + print(f"{path=}") + self = super().from_fits( path=path, sensor=sensor, From 7e1a7fbc2172bf6d181591a66bddbc60c016b87a Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 22:30:27 -0600 Subject: [PATCH 14/17] More debugging --- .github/workflows/tests.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 9258f360..3ccd10ab 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -20,7 +20,8 @@ jobs: - uses: actions/checkout@v4 with: lfs: true - - run: ls -l esis/flights/f1/data/_fits/ + - name: Pull LFS objects + run: git lfs pull - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: From d0d5a661f3e720de84fc158b6fedae6dc4543cb6 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 30 Jul 2025 22:31:00 -0600 Subject: [PATCH 15/17] remove print statement --- esis/data/_level_0/_level_0.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/esis/data/_level_0/_level_0.py b/esis/data/_level_0/_level_0.py index 8984c450..b2182c5f 100644 --- a/esis/data/_level_0/_level_0.py +++ b/esis/data/_level_0/_level_0.py @@ -36,8 +36,6 @@ def from_fits( timeline: None | esis.nsroc.Timeline = None, ) -> Self: - print(f"{path=}") - self = super().from_fits( path=path, sensor=sensor, From 3455fbda52dc1c04d5720307bbbf21bad5114097 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Thu, 31 Jul 2025 08:12:37 -0600 Subject: [PATCH 16/17] more debugging --- .../_level_0/{_level_0_test.py => _level_0_testfoo.py} | 0 esis/flights/f1/data/_level_0/_level_0_test.py | 7 +++++++ esis/flights/f1/data/level_0.py | 0 3 files changed, 7 insertions(+) rename esis/data/_level_0/{_level_0_test.py => _level_0_testfoo.py} (100%) create mode 100644 esis/flights/f1/data/_level_0/_level_0_test.py delete mode 100644 esis/flights/f1/data/level_0.py diff --git a/esis/data/_level_0/_level_0_test.py b/esis/data/_level_0/_level_0_testfoo.py similarity index 100% rename from esis/data/_level_0/_level_0_test.py rename to esis/data/_level_0/_level_0_testfoo.py diff --git a/esis/flights/f1/data/_level_0/_level_0_test.py b/esis/flights/f1/data/_level_0/_level_0_test.py new file mode 100644 index 00000000..54ca2c52 --- /dev/null +++ b/esis/flights/f1/data/_level_0/_level_0_test.py @@ -0,0 +1,7 @@ +import esis + +def test_level_0(): + + lvl0 = esis.flights.f1.data.level_0() + + assert isinstance(lvl0, esis.data.Level_0) diff --git a/esis/flights/f1/data/level_0.py b/esis/flights/f1/data/level_0.py deleted file mode 100644 index e69de29b..00000000 From f2c86e9db4b18f1327489e2e637eb7dd0b396fd2 Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Thu, 31 Jul 2025 08:19:19 -0600 Subject: [PATCH 17/17] why --- esis/data/_level_0/{_level_0_testfoo.py => _level_0_test.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename esis/data/_level_0/{_level_0_testfoo.py => _level_0_test.py} (100%) diff --git a/esis/data/_level_0/_level_0_testfoo.py b/esis/data/_level_0/_level_0_test.py similarity index 100% rename from esis/data/_level_0/_level_0_testfoo.py rename to esis/data/_level_0/_level_0_test.py