From 233d2f55eb982b37d46299d87c735dad90b58130 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Thu, 14 Mar 2024 03:21:32 -0600 Subject: [PATCH 1/5] add level0 --- config.yaml | 1 + punchpipe/flows/level0.py | 28 ++ punchpipe/level0/__init__.py | 0 punchpipe/level0/ccsds.py | 110 ++++++ punchpipe/level0/decode_sqrt.py | 389 +++++++++++++++++++++ punchpipe/level0/tests/__init__.py | 0 punchpipe/level0/tests/test_decode_sqrt.py | 96 +++++ 7 files changed, 624 insertions(+) create mode 100644 punchpipe/level0/__init__.py create mode 100644 punchpipe/level0/ccsds.py create mode 100644 punchpipe/level0/decode_sqrt.py create mode 100644 punchpipe/level0/tests/__init__.py create mode 100644 punchpipe/level0/tests/test_decode_sqrt.py diff --git a/config.yaml b/config.yaml index 395a2bf..5fc6a1a 100644 --- a/config.yaml +++ b/config.yaml @@ -1,4 +1,5 @@ root: "/home/marcus.hughes/running_test/" +input_drop: "dropzone/" file_version: "0.0.1" launcher: diff --git a/punchpipe/flows/level0.py b/punchpipe/flows/level0.py index e69de29..0504bfc 100644 --- a/punchpipe/flows/level0.py +++ b/punchpipe/flows/level0.py @@ -0,0 +1,28 @@ +import os +from glob import glob + +from prefect import flow + +from punchpipe.controlsegment.scheduler import generic_scheduler_flow_logic + + +def level0_query_ready_files(session, pipeline_config: dict): + dropzone = os.path.join(pipeline_config['root'], pipeline_config['input_drop']) + return glob(os.path.join(dropzone, "*.tlm")) + + +def level0_construct_file_info(): + pass + + +def level0_construct_flow_info(): + pass + + +@flow +def level0_scheduler_flow(pipeline_config_path="config.yaml", session=None): + generic_scheduler_flow_logic(level0_query_ready_files, + level0_construct_file_info, + level0_construct_flow_info, + pipeline_config_path, + session=session) diff --git a/punchpipe/level0/__init__.py b/punchpipe/level0/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/punchpipe/level0/ccsds.py b/punchpipe/level0/ccsds.py new file mode 100644 index 0000000..5bbaa26 --- /dev/null +++ b/punchpipe/level0/ccsds.py @@ -0,0 +1,110 @@ +import io + +from ccsdspy import ( + PacketArray, + PacketField, + VariableLength, + FixedLength +) +from ccsdspy.utils import split_by_apid +import pandas as pd + + +def open_and_split_packet_file(path: str) -> dict[int, io.BytesIO]: + with open(path, 'rb') as mixed_file: + stream_by_apid = split_by_apid(mixed_file) + return stream_by_apid + + +def load_packet_def(packet_name, definition_path: str = 'packets/2024-02-09/PUNCH_TLM.xls'): + if packet_name == "SCI_XFI": + return _load_science_packet_def(packet_name, definition_path) + else: + return _load_engineering_packet_def(packet_name, definition_path) + + +def _load_engineering_packet_def(packet_name, definition_path="packets/2024-02-09/PUNCH_TLM.xls"): + contents = pd.read_excel(definition_path, sheet_name=packet_name) + + definition = [] + for row in contents.iterrows(): + name = row[1].iloc[0] + kind = row[1].iloc[2] + kind = 'uint' if name not in("FILL_VALUE", "FSW_MEM_DUMP_DATA") else "fill" + start_byte = row[1].iloc[6] + start_bit = row[1].iloc[7] + size = row[1].iloc[8] + definition.append(PacketField(name=name, data_type=kind, bit_length=size)) + return FixedLength(definition) + + +def _load_science_packet_def(packet_name, definition_path="packets/2024-02-09/PUNCH_TLM.xls"): + sci_pkt = VariableLength([ + PacketField( + name='SCI_XFI_HDR_SCID', + data_type='uint', + bit_length=8 + ), + PacketField( + name='SCI_XFI_FILL_1', + data_type='fill', + bit_length=1 + ), + PacketField( + name='SCI_XFI_FLASH_ADDR', + data_type='uint', + bit_length=15 + ), + PacketField( + name='SCI_XFI_FILL_2', + data_type='fill', + bit_length=2, + ), + PacketField( + name='SCI_XFI_TIME_QUAL', + data_type='uint', + bit_length=2 + ), + PacketField( + name='SCI_XFI_GPS_TIME_MS', + data_type='uint', + bit_length=20, + ), + PacketField( + name='SCI_XFI_GPS_TIME_S', + data_type='uint', + bit_length=32, + ), + PacketField( + name='SCI_XFI_HDR_GRP', + data_type='uint', + bit_length=8, + ), + PacketField( + name='SCI_XFI_ACQ_SET', + data_type='uint', + bit_length=32, + ), + PacketField( + name='SCI_XFI_COM_SET', + data_type='uint', + bit_length=16, + ), + PacketField( + name='SCI_XFI_FILL_3', + data_type='fill', + bit_length=8, + ), + PacketArray( + name='SCI_XFI_IMG_DATA', + data_type='uint', + bit_length=8, + array_shape='expand' + ) + ]) + + return sci_pkt + + +def process_telemetry_file(telemetry_file_path): + apid_separated_tlm = open_and_split_packet_file(telemetry_file_path) diff --git a/punchpipe/level0/decode_sqrt.py b/punchpipe/level0/decode_sqrt.py new file mode 100644 index 0000000..fe3ea9d --- /dev/null +++ b/punchpipe/level0/decode_sqrt.py @@ -0,0 +1,389 @@ +import os.path +from typing import Tuple, Union + +import numpy as np +from prefect import get_run_logger, task + +from punchbowl.data import PUNCHData + +TABLE_PATH = os.path.dirname(__file__) + "/decoding_tables/" + + +def decode_sqrt( + data: Union[np.ndarray, float], + from_bits: int = 16, + to_bits: int = 12, + ccd_gain: float = 1 / 4.3, + ccd_offset: float = 100, + ccd_read_noise: float = 17, + overwrite_table: bool = False) -> np.ndarray: + """ + Square root decode between specified bitrate values + + Parameters + ---------- + data + Input encoded data array + from_bits + Specified bitrate of encoded image to unpack + to_bits + Specified bitrate of output data (decoded) + ccd_gain + CCD gain [photons / DN] + ccd_offset + CCD bias level [DN] + ccd_read_noise + CCD read noise level [DN] + overwrite_table + Toggle to regenerate and overwrite existing decoding table + + Returns + ------- + np.ndarray + Square root decoded version of the input image + + """ + + table_name = ( + TABLE_PATH + + "tab_fb" + + str(from_bits) + + "_tb" + + str(to_bits) + + "_g" + + str(1 / ccd_gain) + + "_b" + + str(ccd_offset) + + "_r" + + str(ccd_read_noise) + + ".npy" + ) + + # Check for an existing table, otherwise generate one + if not os.path.isfile(table_name) or overwrite_table: + table = generate_decode_sqrt_table(from_bits, to_bits, ccd_gain, + ccd_offset, ccd_read_noise) + + # Make the directory if it doesn't exist + if not os.path.isdir(TABLE_PATH): + os.makedirs(TABLE_PATH, exist_ok=True) + + np.save(table_name, table) + else: + table = np.load(table_name) + + return decode_sqrt_by_table(data, table) + + +def encode_sqrt(data: Union[np.ndarray, float], from_bits: int = 16, to_bits: int = 12) -> np.ndarray: + """ + Square root encode between specified bitrate values + + Parameters + ---------- + data + Input data array + from_bits + Specified bitrate of original input image + to_bits + Specified bitrate of output encoded image + + Returns + ------- + np.ndarray + Encoded version of input data + + """ + + data = np.round(data).astype(np.int32).clip(0, None) + factor = np.array(2 ** (2 * to_bits - from_bits)) + data_scaled_by_factor = np.round(data * factor).astype(np.int32) + + return np.floor(np.sqrt(data_scaled_by_factor)).astype(np.int32) + + +def decode_sqrt_simple(data: Union[np.ndarray, float], from_bits: int = 16, to_bits: int = 12) -> np.ndarray: + """ + Performs a simple decoding using the naive squaring strategy + + Parameters + ---------- + data + Input data array + from_bits + Specified bitrate of original input image + to_bits + Specified bitrate of output encoded image + + Returns + ------- + np.ndarray + Decoded version of input data + + """ + + data = np.round(data).astype(np.int32).clip(0, None) + factor = 2.0 ** (2 * to_bits - from_bits) + + return np.round(np.square(data) / factor).astype(np.int32) + + +def noise_pdf( + data_value: Union[np.ndarray, float], + ccd_gain: float = 1 / 4.3, + ccd_offset: float = 100, + ccd_read_noise: float = 17, + n_sigma: int = 5, + n_steps: int = 10000) -> Tuple: + """ + Generates a probability distribution function (pdf) from an input data value + + Parameters + ---------- + data_value + Input data value + ccd_gain + CCD gain [DN / electron] + ccd_offset + CCD bias level [DN] + ccd_read_noise + CCD read noise level [DN] + n_sigma + Number of sigma steps + n_steps + Number of data steps + + + Returns + ------- + np.ndarray + Data step distribution + normal + Data normal distribution + + """ + + # Use camera calibration to get an e-count + electrons = np.clip((data_value - ccd_offset) / ccd_gain, 1, None) + + # Shot noise, converted back to DN + poisson_sigma = np.sqrt(electrons) * ccd_gain + + # Total sigma is quadrature sum of fixed & shot + sigma = np.sqrt(poisson_sigma ** 2 + ccd_read_noise ** 2) + + dn_steps = np.arange(-n_sigma * sigma, n_sigma * sigma, sigma * n_sigma * 2 / n_steps) + + # Explicitly calculate the Gaussian/normal PDF at each step + normal = np.exp(-dn_steps * dn_steps / sigma / sigma / 2) + + # Easier to normalize numerically than to account for missing tails + normal = normal / np.sum(normal) + + return data_value + dn_steps, normal + + +def mean_b_offset( + data_value: float, + from_bits: int = 16, + to_bits: int = 12, + ccd_gain: float = 1 / 4.3, + ccd_offset: float = 100, + ccd_read_noise: float = 17) -> float: + """ + Compute an offset from the naive and robust decoding processes + + Parameters + ---------- + data_value + Input data value [DN] + from_bits + Specified bitrate of encoded image to unpack + to_bits + Specified bitrate of output data (decoded) + ccd_gain + CCD gain [DN / electron] + ccd_offset + CCD bias level [DN] + ccd_read_noise + CCD read noise level [DN] + + Returns + ------- + float + Generated decoding value for use in constructing a decoding table + + """ + naive_decoded_value = decode_sqrt_simple(data_value, from_bits, to_bits) + + # Generate distribution around naive value + (values, weights) = noise_pdf(naive_decoded_value, ccd_gain, ccd_offset, ccd_read_noise) + + # Ignore values below the offset -- which break the noise model + weights = weights * (values >= ccd_offset) + + if np.sum(weights) < 0.95: + return 0 + + weights = weights / np.sum(weights) + + # Encode the entire value distribution + data_values = encode_sqrt(values, from_bits, to_bits) + + # Decode the entire value distribution to find the net offset + net_offset = decode_sqrt_simple(data_values, from_bits, to_bits) + + # Expected value of the entire distribution + expected_value = np.sum(net_offset * weights) + + # Return ΔB. + return expected_value - naive_decoded_value + + +def decode_sqrt_corrected( + data_value: float, + from_bits: int = 16, + to_bits: int = 12, + ccd_gain: float = 1 / 4.3, + ccd_offset: float = 100, + ccd_read_noise: float = 17) -> float: + """ + Compute an individual decoding value for an input data value + + Parameters + ---------- + data_value + Input data value [DN] + from_bits + Specified bitrate of encoded image to unpack + to_bits + Specified bitrate of output data (decoded) + ccd_gain + CCD gain [DN / electron] + ccd_offset + CCD bias level [DN] + ccd_read_noise + CCD read noise level [DN] + + Returns + ------- + float + Generated decoding value for use in constructing a decoding table + + """ + + s1p = decode_sqrt_simple(data_value + 1, from_bits, to_bits) + s1n = decode_sqrt_simple(data_value - 1, from_bits, to_bits) + + width = (s1p - s1n) / 4 + + fixed_sigma = np.sqrt(ccd_read_noise ** 2 + width ** 2) + + of = mean_b_offset(data_value, from_bits, to_bits, ccd_gain, ccd_offset, fixed_sigma) + + return decode_sqrt_simple(data_value, from_bits, to_bits) - of + + +def generate_decode_sqrt_table( + from_bits: int = 16, + to_bits: int = 12, + ccd_gain: float = 1 / 4.3, + ccd_offset: float = 100, + ccd_read_noise: float = 17) -> np.ndarray: + """ + Generates a square root decode table between specified bitrate values and CCD parameters + + Parameters + ---------- + from_bits + Specified bitrate of encoded image to unpack + to_bits + Specified bitrate of output data (decoded) + ccd_gain + CCD gain [DN / electron] + ccd_offset + CCD bias level [DN] + ccd_read_noise + CCD read noise level [DN] + + Returns + ------- + table + Generated square root decoding table + + """ + + table = np.zeros(2 ** to_bits) + + for i in range(2 ** to_bits): + table[i] = decode_sqrt_corrected(i, from_bits, to_bits, ccd_gain, ccd_offset, ccd_read_noise) + + return table + + +def decode_sqrt_by_table(data: Union[np.ndarray, float], table: np.ndarray) -> np.ndarray: + """ + Generates a square root decode table between specified bitrate values and CCD parameters + + Parameters + ---------- + data + Input encoded data array + table + Square root decoding table + + Returns + ------- + np.ndarray + Decoded version of input data + + """ + + data = np.round(data).astype(np.int32).clip(0, table.shape[0]) + + return table[data] + + +@task +def decode_sqrt_data(data_object: PUNCHData, overwrite_table: bool = False) -> PUNCHData: + """Prefect task in the pipeline to decode square root encoded data + + Parameters + ---------- + data_object : PUNCHData + the object you wish to decode + overwrite_table + Toggle to regenerate and overwrite existing decoding table + + Returns + ------- + PUNCHData + a modified version of the input with the data square root decoded + """ + + logger = get_run_logger() + logger.info("square root decoding started") + + data = data_object.data + + from_bits = data_object.meta["RAWBITS"].value + to_bits = data_object.meta["COMPBITS"].value + + ccd_gain = data_object.meta["GAINCMD"].value + ccd_offset = data_object.meta["OFFSET"].value + ccd_read_noise = 17 # DN + + decoded_data = decode_sqrt(data, + from_bits=from_bits, + to_bits=to_bits, + ccd_gain=ccd_gain, + ccd_offset=ccd_offset, + ccd_read_noise=ccd_read_noise, + overwrite_table=overwrite_table) + + data_object = data_object.duplicate_with_updates(data=decoded_data) + + logger.info("square root decoding finished") + data_object.meta.history.add_now("LEVEL0-decode-sqrt", "image square root decoded") + + return data_object diff --git a/punchpipe/level0/tests/__init__.py b/punchpipe/level0/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/punchpipe/level0/tests/test_decode_sqrt.py b/punchpipe/level0/tests/test_decode_sqrt.py new file mode 100644 index 0000000..5d3a5c9 --- /dev/null +++ b/punchpipe/level0/tests/test_decode_sqrt.py @@ -0,0 +1,96 @@ +from datetime import datetime + +import numpy as np +import pytest +from astropy.nddata import StdDevUncertainty +from astropy.wcs import WCS +from prefect.logging import disable_run_logger +from pytest import fixture + +from punchbowl.data import NormalizedMetadata, PUNCHData +from punchpipe.level0.decode_sqrt import decode_sqrt, decode_sqrt_data, decode_sqrt_simple, encode_sqrt + + +# Some test inputs +@fixture +def sample_punchdata(): + """ + Generate a sample PUNCHData object for testing + """ + + data = np.random.random([2048, 2048]) + uncertainty = StdDevUncertainty(np.sqrt(np.abs(data))) + wcs = WCS(naxis=2) + wcs.wcs.ctype = "HPLN-ARC", "HPLT-ARC" + wcs.wcs.cunit = "deg", "deg" + wcs.wcs.cdelt = 0.01, 0.01 + wcs.wcs.crpix = 1024, 1024 + wcs.wcs.crval = 0, 0 + wcs.wcs.cname = "HPC lon", "HPC lat" + meta = NormalizedMetadata.load_template("PM1", "0") + meta['DATE-OBS'] = str(datetime(2023, 1, 1, 0, 0, 1)) + + punchdata_obj = PUNCHData(data=data, uncertainty=uncertainty, wcs=wcs, meta=meta) + + punchdata_obj.meta['RAWBITS'] = 16 + punchdata_obj.meta['COMPBITS'] = 10 + punchdata_obj.meta['GAINCMD'] = 1.0/4.3 + punchdata_obj.meta['OFFSET'] = 100 + + return punchdata_obj + + +def test_encoding(): + arr_dim = 2048 + arr = np.random.random([arr_dim, arr_dim]) * (2 ** 16) + + encoded_arr = encode_sqrt(arr, from_bits=16, to_bits=10) + + assert encoded_arr.shape == arr.shape + assert np.max(encoded_arr) <= 2 ** 10 + + +def test_decoding(): + arr_dim = 2048 + arr = np.random.random([arr_dim, arr_dim]) * (2 ** 10) + + decoded_arr = decode_sqrt_simple(arr, from_bits=10, to_bits=16) + + assert decoded_arr.shape == arr.shape + assert np.max(decoded_arr) <= 2 ** 16 + + +@pytest.mark.parametrize('from_bits, to_bits', [(16, 10), (16, 11), (16, 12)]) +def test_encode_then_decode(from_bits, to_bits): + arr_dim = 2048 + ccd_gain = 1.0 / 4.3 # DN/electron + ccd_offset = 100 # DN + ccd_read_noise = 17 # DN + + original_arr = (np.random.random([arr_dim, arr_dim]) * (2 ** from_bits)).astype(int) + + encoded_arr = encode_sqrt(original_arr, from_bits, to_bits) + decoded_arr = decode_sqrt(encoded_arr, + from_bits=from_bits, + to_bits=to_bits, + ccd_gain=ccd_gain, + ccd_offset=ccd_offset, + ccd_read_noise=ccd_read_noise) + + noise_tolerance = np.sqrt(original_arr / ccd_gain) * ccd_gain + + test_coords = np.where(original_arr > 150) + + assert np.all(np.abs(original_arr[test_coords] - decoded_arr[test_coords]) <= noise_tolerance[test_coords]) + + +@pytest.mark.prefect_test +def test_decode_sqrt_data_task(sample_punchdata): + """ + Test the decode_sqrt_data prefect task using a test harness + """ + + with disable_run_logger(): + output_punchdata = decode_sqrt_data.fn(sample_punchdata, overwrite_table=True) + assert isinstance(output_punchdata, PUNCHData) + assert output_punchdata.data.shape == (2048, 2048) From 9ee6d05e1546daaac9520ed8c6ad4fc8db769584 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Thu, 14 Mar 2024 03:37:32 -0600 Subject: [PATCH 2/5] updates requirements to setup.py --- .github/workflows/ci.yaml | 5 ++--- .github/workflows/docs.yaml | 3 +-- docs/requirements.txt | 5 ----- requirements.txt | 12 ------------ requirements_dev.txt | 18 ------------------ setup.py | 24 +++++++++++++++++++----- 6 files changed, 22 insertions(+), 45 deletions(-) delete mode 100644 docs/requirements.txt delete mode 100644 requirements.txt delete mode 100644 requirements_dev.txt diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 88a9fdb..da1b4f0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -32,8 +32,7 @@ jobs: eval `ssh-agent -s` ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' python -m pip install --upgrade pip - python -m pip install flake8 pytest pytest-cov hypothesis coverage freezegun pytest-mock-resources[mysql] - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + pip install ".[dev]" - name: Lint with flake8 run: | # stop the build if there are Python syntax errors or undefined names @@ -42,7 +41,7 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - pip install . + pip install "." pytest --cov - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index e463589..a73f72a 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -23,8 +23,7 @@ jobs: run: | eval `ssh-agent -s` ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' - pip install -r ./docs/requirements.txt - pip install -r requirements.txt + pip install -r ".[docs]" # Build the book - name: Sphinx build diff --git a/docs/requirements.txt b/docs/requirements.txt deleted file mode 100644 index 11fa69b..0000000 --- a/docs/requirements.txt +++ /dev/null @@ -1,5 +0,0 @@ -sphinx -pydata-sphinx-theme -sphinx-autoapi -sphinx-favicon -sphinxcontrib-mermaid \ No newline at end of file diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 3e06c09..0000000 --- a/requirements.txt +++ /dev/null @@ -1,12 +0,0 @@ -prefect -git+ssh://git@github.com/punch-mission/punchbowl.git#egg=punchbowl -pydantic==1.10.12 -pymysql -sqlalchemy -pyyaml -dash -pandas -plotly -numpy -coolname -datapane diff --git a/requirements_dev.txt b/requirements_dev.txt deleted file mode 100644 index 515415a..0000000 --- a/requirements_dev.txt +++ /dev/null @@ -1,18 +0,0 @@ -git+ssh://git@github.com/punch-mission/punchbowl.git#egg=punchbowl -prefect -pydantic -pymysql -sqlalchemy -pyyaml -dash -pandas -plotly -numpy -coolname -datapane - -pytest -coverage -pytest-mock-resources[mysql] -freezegun -pre-commit diff --git a/setup.py b/setup.py index 7a39cf3..e5fe5f5 100644 --- a/setup.py +++ b/setup.py @@ -19,17 +19,31 @@ long_description=long_description, long_description_content_type='text/markdown', install_requires=[ + 'git+ssh://git@github.com/punch-mission/punchbowl.git#egg=punchbowl', 'prefect', 'pymysql', + 'pandas', 'pydantic==1.10.12', 'sqlalchemy', - 'punchbowl', - 'datapane', + 'dash', + 'coolname', + 'numpy', 'plotly', 'pyyaml'], extras_require={ - 'dev': [], - 'test': ['pytest', 'coverage', 'pytest-mock-resources[mysql]', 'freezegun'], - 'docs': ['sphinx', 'sphinx-rtd-theme', 'sphinx-automodapi'] + 'dev': ["flake8", + 'pre-commit', + 'hypothesis', + 'pytest', + 'coverage', + 'pytest-cov', + 'pytest-mock-resources[mysql]', + 'freezegun'], + 'docs': ['sphinx', + 'pydata-sphinx-theme', + 'sphinx-autoapi', + 'sphinx-favicon', + 'sphinxcontrib-mermaid', + 'sphinx-automodapi'] }, ) From 944f9f4eb57c85aeae035a8e1a1e97082012f162 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Thu, 14 Mar 2024 03:40:36 -0600 Subject: [PATCH 3/5] fix private dependency --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index e5fe5f5..2bcccc4 100644 --- a/setup.py +++ b/setup.py @@ -19,7 +19,7 @@ long_description=long_description, long_description_content_type='text/markdown', install_requires=[ - 'git+ssh://git@github.com/punch-mission/punchbowl.git#egg=punchbowl', + 'punchbowl @ git+ssh://git@github.com/punch-mission/punchbowl@main', 'prefect', 'pymysql', 'pandas', From 84857644e4825943658b42b5f37e994b21435358 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Thu, 14 Mar 2024 03:44:30 -0600 Subject: [PATCH 4/5] make ci use private key always --- .github/workflows/ci.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index da1b4f0..3522490 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -41,7 +41,9 @@ jobs: flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics - name: Test with pytest run: | - pip install "." + eval `ssh-agent -s` + ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' + pip install . pytest --cov - name: Upload coverage to Codecov uses: codecov/codecov-action@v4 From f143a332ad7a603cd1c23c3d7a5ab4c5fd22e753 Mon Sep 17 00:00:00 2001 From: Marcus Hughes Date: Thu, 14 Mar 2024 03:49:27 -0600 Subject: [PATCH 5/5] fix docs ci --- .github/workflows/docs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/docs.yaml b/.github/workflows/docs.yaml index a73f72a..6620531 100644 --- a/.github/workflows/docs.yaml +++ b/.github/workflows/docs.yaml @@ -23,7 +23,7 @@ jobs: run: | eval `ssh-agent -s` ssh-add - <<< '${{ secrets.PRIVATE_SSH_KEY }}' - pip install -r ".[docs]" + pip install ".[docs]" # Build the book - name: Sphinx build