-
Notifications
You must be signed in to change notification settings - Fork 0
support adcmod sibling directories #2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,173 @@ | ||
| """Tests for fileset path resolution, including corrected (adcmod) ADC files.""" | ||
|
|
||
| import asyncio | ||
| import os | ||
| import shutil | ||
|
|
||
| import pytest | ||
|
|
||
| from ifcbkit.fileset import SyncIfcbDataDirectory, AsyncIfcbDataDirectory | ||
|
|
||
| PID = 'D20170426T164105_IFCB009' | ||
| DAY = 'D20170426' | ||
|
|
||
| # Real I-style fixture (the actual adcmod use case). Its containing directory | ||
| # name is what the adcmod tree mirrors as the "day" subdirectory. | ||
| I_PID = 'IFCB5_2012_028_081515' | ||
| I_DAY = 'IFCB5_2012_028' | ||
| I_FIXTURE_DIR = os.path.join(os.path.dirname(__file__), 'data', I_PID) | ||
|
|
||
|
|
||
| def _copy_i_fileset(day_dir): | ||
| os.makedirs(day_dir, exist_ok=True) | ||
| for ext in ('hdr', 'adc', 'roi'): | ||
| shutil.copy( | ||
| os.path.join(I_FIXTURE_DIR, f'{I_PID}.{ext}'), | ||
| os.path.join(day_dir, f'{I_PID}.{ext}'), | ||
| ) | ||
|
|
||
|
|
||
| def _make_fileset(dirpath, pid): | ||
| os.makedirs(dirpath, exist_ok=True) | ||
| for ext in ('hdr', 'adc', 'roi'): | ||
| with open(os.path.join(dirpath, f'{pid}.{ext}'), 'w') as f: | ||
| f.write('') | ||
|
|
||
|
|
||
| def _make_adcmod(adcmod_root, day, pid, content='mod'): | ||
| day_dir = os.path.join(adcmod_root, day) | ||
| os.makedirs(day_dir, exist_ok=True) | ||
| path = os.path.join(day_dir, f'{pid}.adc.mod') | ||
| with open(path, 'w') as f: | ||
| f.write(content) | ||
| return path | ||
|
|
||
|
|
||
| def test_no_adcmod_uses_raw_adc(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(PID)['adc'] == str(root / DAY / f'{PID}.adc') | ||
|
|
||
|
|
||
| def test_adcmod_sibling_of_data_dir(tmp_path): | ||
| # <root>/data/<day>/<pid>.adc and <root>/adcmod/<day>/<pid>.adc.mod | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(PID)['adc'] == mod | ||
|
|
||
|
|
||
| def test_adcmod_with_year_level(tmp_path): | ||
| # <root>/data/2017/<day>/... and <root>/adcmod/<day>/<pid>.adc.mod | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / '2017' / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(PID)['adc'] == mod | ||
|
|
||
|
|
||
| def test_adcmod_appears_in_list(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| entries = list(dd.list()) | ||
| assert len(entries) == 1 | ||
| assert entries[0]['adc'] == mod | ||
|
|
||
|
|
||
| def test_adcmod_inside_root_is_ignored(tmp_path): | ||
| # adcmod is strictly a sibling of root_path; one nested inside root (here a | ||
| # sibling of the intermediate year directory) must not be used. | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / '2017' / DAY), PID) | ||
| _make_adcmod(str(root / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(PID)['adc'] == str(root / '2017' / DAY / f'{PID}.adc') | ||
|
|
||
|
|
||
| def test_adcmod_sibling_of_nonroot_ancestor_is_ignored(tmp_path): | ||
| # <root> is <tmp>/raw/data, so only <tmp>/raw/adcmod counts -- an adcmod | ||
| # sibling of <tmp>/raw's own parent must not be used. | ||
| root = tmp_path / 'raw' / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(PID)['adc'] == str(root / DAY / f'{PID}.adc') | ||
|
|
||
|
|
||
| def test_adcmod_sibling_of_root_with_trailing_slash(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = SyncIfcbDataDirectory(str(root) + os.sep) | ||
| assert dd.paths(PID)['adc'] == mod | ||
|
|
||
|
|
||
| def test_async_adcmod_resolution(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| dd = AsyncIfcbDataDirectory(str(root)) | ||
| paths = asyncio.run(dd.paths(PID)) | ||
| assert paths['adc'] == mod | ||
|
|
||
|
|
||
| # --- I-style bins (the real adcmod use case) --- | ||
|
|
||
| def test_istyle_adcmod_path_resolves(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _copy_i_fileset(str(root / I_DAY)) | ||
| # corrected ADC is a byte-identical copy of the raw ADC | ||
| raw_adc = os.path.join(I_FIXTURE_DIR, f'{I_PID}.adc') | ||
| mod = _make_adcmod( | ||
| str(tmp_path / 'adcmod'), I_DAY, I_PID, | ||
| content=open(raw_adc).read(), | ||
| ) | ||
|
joefutrelle marked this conversation as resolved.
|
||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(I_PID)['adc'] == mod | ||
|
|
||
|
|
||
| def test_istyle_read_images_through_adcmod(tmp_path): | ||
| # End-to-end: I-style stitching must work reading the corrected ADC. | ||
| root = tmp_path / 'data' | ||
| _copy_i_fileset(str(root / I_DAY)) | ||
| raw_adc = os.path.join(I_FIXTURE_DIR, f'{I_PID}.adc') | ||
|
|
||
| # baseline: raw ADC (no adcmod sibling) | ||
| baseline = SyncIfcbDataDirectory(str(root)).read_images(I_PID) | ||
| assert len(baseline) > 0 | ||
|
|
||
| # with a byte-identical corrected ADC present, results must match | ||
| _make_adcmod(str(tmp_path / 'adcmod'), I_DAY, I_PID, content=open(raw_adc).read()) | ||
|
joefutrelle marked this conversation as resolved.
|
||
| dd = SyncIfcbDataDirectory(str(root)) | ||
| assert dd.paths(I_PID)['adc'].endswith('.adc.mod') | ||
| corrected = dd.read_images(I_PID) | ||
| assert set(corrected.keys()) == set(baseline.keys()) | ||
| for t in baseline: | ||
| assert corrected[t].size == baseline[t].size | ||
|
|
||
|
|
||
| def test_istyle_corrected_adc_content_is_used(tmp_path): | ||
| # Prove the corrected ADC (not the raw one) drives the output: zero out | ||
| # one ROI's width in the .adc.mod so that target drops from the results. | ||
| root = tmp_path / 'data' | ||
| _copy_i_fileset(str(root / I_DAY)) | ||
| raw_adc = os.path.join(I_FIXTURE_DIR, f'{I_PID}.adc') | ||
|
|
||
| baseline = SyncIfcbDataDirectory(str(root)).read_images(I_PID) | ||
| dropped = sorted(baseline.keys())[0] | ||
|
|
||
| # I-style: width at column 11, height at 12 (0-based) | ||
| lines = open(raw_adc).read().splitlines() | ||
|
joefutrelle marked this conversation as resolved.
|
||
| fields = lines[dropped - 1].split(',') | ||
| fields[11] = '0' | ||
| fields[12] = '0' | ||
| lines[dropped - 1] = ','.join(fields) | ||
| _make_adcmod(str(tmp_path / 'adcmod'), I_DAY, I_PID, content='\n'.join(lines) + '\n') | ||
|
|
||
| corrected = SyncIfcbDataDirectory(str(root)).read_images(I_PID) | ||
| assert dropped in baseline | ||
| assert dropped not in corrected | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,73 @@ | ||
| """Tests for filesystem-backed stores, including corrected (adcmod) ADC files.""" | ||
|
|
||
| import asyncio | ||
| import os | ||
|
|
||
| from ifcbkit.stores.filesystem import AsyncFilesystemBinStore | ||
|
|
||
| PID = 'D20170426T164105_IFCB009' | ||
| DAY = 'D20170426' | ||
|
|
||
|
|
||
| def _make_fileset(dirpath, pid): | ||
| os.makedirs(dirpath, exist_ok=True) | ||
| for ext in ('hdr', 'adc', 'roi'): | ||
| with open(os.path.join(dirpath, f'{pid}.{ext}'), 'w') as f: | ||
| f.write('') | ||
|
|
||
|
|
||
| def _make_adcmod(adcmod_root, day, pid, content='mod'): | ||
| day_dir = os.path.join(adcmod_root, day) | ||
| os.makedirs(day_dir, exist_ok=True) | ||
| path = os.path.join(day_dir, f'{pid}.adc.mod') | ||
| with open(path, 'w') as f: | ||
| f.write(content) | ||
| return path | ||
|
|
||
|
|
||
| def test_bin_store_no_adcmod_uses_raw_adc(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| path = asyncio.run(store.get_path(f'{PID}.adc')) | ||
| assert path == str(root / DAY / f'{PID}.adc') | ||
|
|
||
|
|
||
| def test_bin_store_resolves_adcmod(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| assert asyncio.run(store.get_path(f'{PID}.adc')) == mod | ||
|
|
||
|
|
||
| def test_bin_store_get_reads_adcmod_content(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID, content='corrected') | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| assert asyncio.run(store.get(f'{PID}.adc')) == b'corrected' | ||
|
|
||
|
|
||
| def test_bin_store_adcmod_does_not_affect_hdr_or_roi(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| assert asyncio.run(store.get_path(f'{PID}.hdr')) == str(root / DAY / f'{PID}.hdr') | ||
| assert asyncio.run(store.get_path(f'{PID}.roi')) == str(root / DAY / f'{PID}.roi') | ||
|
|
||
|
|
||
| def test_bin_store_adcmod_with_year_level(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / '2017' / DAY), PID) | ||
| mod = _make_adcmod(str(tmp_path / 'adcmod'), DAY, PID) | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| assert asyncio.run(store.get_path(f'{PID}.adc')) == mod | ||
|
|
||
|
|
||
| def test_bin_store_exists_unknown_bin(tmp_path): | ||
| root = tmp_path / 'data' | ||
| _make_fileset(str(root / DAY), PID) | ||
| store = AsyncFilesystemBinStore(str(root)) | ||
| assert asyncio.run(store.get_path('D20991231T000000_IFCB009.adc')) is None |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.