Repository navigation
Conversation
The lock refresh in 4c2d59d floated flake8 7.1 -> 7.3 (pyflakes 3.2 -> 3.4), which added F824. These declarations were for names only read, never assigned, in the inner scope, so removing them does not change behavior. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…extension, typed lookups, single Excel open - Scan, rewrite, and append only within the reader's logical rows (before the first empty row). - Extend an existing ProtectedDonor sheet's headers for copied fields, or reject unsafe shapes before mutating. - Resolve non-token references (UUID/accession) as ProtectedDonors via workbook identifiers or typed portal lookup. - Report permission/outage lookup failures distinctly from definitive absence. - Open the Excel workbook once in StructuredDataSet so the progress counting pass cannot pre-create the staged output.
pytest.ini (re-added in fb05879 with only the `last` marker) takes precedence over [tool.pytest.ini_options] in pyproject.toml, silently disabling basetemp, redis_exec, markers, and filterwarnings. On macOS the missing --basetemp=/tmp/pytest makes pytest-redis' unix socket path exceed 104 chars (UnixSocketTooLong), and unregistered markers produce ~150 PytestUnknownMarkWarnings. Move the `last` marker into pyproject.toml and update filterwarnings for current third-party deprecation warnings (pkg_resources is now a UserWarning in setuptools 81; declare_namespace, cgi via WebOb, prettytable constants via pip-licenses). Drop the obsolete Python 3.7 boto3 filter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Developers commonly export IDENTITY locally (conftest needs it to load env config), which conflicts with the identity the ini builder sets and causes a RuntimeError. Clear it for the duration of the test. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CPython 3.12.15 made urllib's HTTPPasswordMgr scheme-aware, changing the internal passwd dict key from ((authority, path),) to ((scheme, authority, path),). The test indexed that private dict directly and broke with KeyError on the 3.12 CI leg. Use find_user_password(), which works across Python versions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ed-path clobbering
Coverage Report for CI Build 38962637325Coverage increased (+0.9%) to 75.532%Details
Uncovered Changes
Coverage Regressions3 previously-covered lines in 3 files lost coverage.
Coverage Stats
💛 - Coveralls |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Intent
Validate the compatibility fix on the existing ProtectedDonor implementation in #339: submitr passes allow_existing_staging_path when it supplies an owned staging workbook, so dcicutils CustomExcel must accept that option, replace the staged output safely, and initialize its workbook state early enough that construction failures do not trigger an AttributeError in Excel.del. Preserve the existing PR339 behavior and ensure the focused ProtectedDonor tests pass.
What Changed
dcicutils/submitr/donor_transformer.py(ProtectedDonorWorkbookTransformer,analyze_protected_donors). It converts Donor references to ProtectedDonor in the Demographic, DeathCircumstances, FamilyHistory, MedicalHistory, and TissueCollection sheets, and adds the matching ProtectedDonor rows. It only scans the logical rows the reader ingests, resolves UUID/accession identifiers through the portal, and raisesProtectedDonorLookupErrorfor permission or lookup failures. Tests are intest/test_protected_donor_transform.py.CustomExcelnow accepts three opt-in options:transform_protected_donor,transformed_workbook_path, andallow_existing_staging_path.CustomExcel.with_portal(portal, **options)passes them through. Workbook state is set beforeExcel.__init__runs, so a failed construction no longer raisesAttributeErrorinExcel.__del__. The transformed workbook is saved atomically (temp file plusos.replace) and never overwrites the input workbook. An existing output path is replaced only whenallow_existing_staging_path=True.StructuredDataSetnow opens an Excel workbook once for both the progress-count pass and the parse pass. It also applies the specified schema order to multi-schema JSON files and guards auniquetypeinfo lookup. Other changes:nonlocal/globaldeclarations flagged by pyflakes F824.lastmarker frompytest.iniintopyproject.toml.jh_utilsanddeployment_utilstests less sensitive to the environment.poetry.lock.Risk Assessment
✅ Low: The fix is small and does what the intent asks: CustomExcel accepts and forwards allow_existing_staging_path, sets _workbook before super().init so Excel.del is safe, and saves atomically with temp-file cleanup; the main gap is that the regression tests covering this were removed earlier and not restored.
Testing
I ran the focused ProtectedDonor and CustomExcel tests, adding three regression tests that fail before the fix and pass after it. They cover replacing an owned staging path, keeping the original file and cleaning up when a save fails, and construction failures no longer triggering an AttributeError in
__del__. I also ran a script that mimics submitr: it parses a workbook throughStructuredDataSetwith a pre-created staging file and confirms the transformed output, that the flag-less path still rejects the existing file, and that no exceptions are raised in__del__. Everything passed. There is no UI surface, so the evidence is a CLI transcript.Evidence: submitr-style staging replacement transcript
staging file pre-exists: True size 0 parsed Demographic.donor: A_PROTECTED-DONOR_1 staged sheets: ['Donor', 'Demographic', 'ProtectedDonor'] staged ProtectedDonor ids: ['A_PROTECTED-DONOR_1'] dir contents: no temp leftovers without allow flag -> ValueError: True bad kwarg -> TypeError: Excel.init() got an unexpected keyword argument 'bogus_option' unraisable exceptions in del: []Evidence: Demo script
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
dcicutils/submitr/custom_excel.py:107- The compatibility fix has no regression tests. Commit e883d1c removedtest_save_transformed_workbook_allows_owned_staging_pathandtest_failed_save_does_not_damage_existing_target, and 93d1927 brings backallow_existing_staging_pathand the temp-file/os.replace save without bringing those tests back. Nothing in test/test_protected_donor_transform.py passesallow_existing_staging_path=True. Nothing checks that a failed save leaves the existing target alone and deletes the temp file. Nothing checks that a construction failure (for example, a TypeError from a bad argument to Excel.init, or a missing file) no longer raises AttributeError in Excel.del. The intent names all three behaviors. Add behavioral tests: (1) a placeholder pre-created by submitr is replaced with the transformed workbook when allow_existing_staging_path=True, and the call still raises 'already exists' without the flag; (2) when workbook.save is monkeypatched to raise, the target bytes are unchanged and no.<name>.*.xlsxtemp file is left behind; (3) CustomExcel(transform_protected_donor=True) with a bad file argument raises the original error, and garbage collection raises no AttributeError (check with pytest's unraisable-exception warning or sys.unraisablehook).dcicutils/submitr/custom_excel.py:120- With allow_existing_staging_path=True, the staging path is only written when the transform actually changes the workbook (if transformed and ...). If submitr pre-creates an empty or placeholder staging file and the workbook has no Donor references to convert, the placeholder is left as is. CustomExcel also exposes no attribute that tells the caller whether a transform happened. If submitr uploads or reads the staging path without checking, it could use the placeholder instead of the original workbook. Confirm that submitr handles the 'nothing transformed' case, for example by falling back to the input file when the staging file is unchanged, or decide whether CustomExcel should expose the transformed flag.dcicutils/submitr/custom_excel.py:159- tempfile.mkstemp creates the file with mode 0600, and os.replace keeps that mode. The staged workbook therefore ends up owner-only instead of following the umask, as a direct workbook.save would. This is fine for a submitr-owned temp staging file, but it differs from the earlier direct-save behavior if another process or user reads the output.✅ **Test** - passed
✅ No issues found.
NO_SERVER_FIXTURES=TRUE USE_SAMPLE_ENVUTILS=TRUE poetry run pytest test/test_protected_donor_transform.py test/test_custom_excel.py -q(49 passed, including the new tests)New testtest_owned_staging_path_is_replaced_when_existing_path_is_allowed: a stale existing staged workbook is replaced with the transformed ProtectedDonor workbook and no temp files remainNew testtest_failed_save_to_owned_staging_path_keeps_existing_file_and_leaves_no_temporary: a save that fails partway leaves the original staged bytes intact and removes the temp fileNew testtest_construction_failure_does_not_raise_attribute_error_in_excel_del: an unsupported kwarg raises TypeError with no unraisable AttributeError fromExcel.__del__Regression check: replaced custom_excel.py with the pre-fix version (HEAD~1) and reran; all 3 new tests failed, including the reproduced'CustomExcel' object has no attribute '_workbook'error, then restored the fileExisting PR339 testtest_repeated_construction_still_cannot_clobber_the_staged_pathstill passes, so overwriting is still refused without the flagEnd-to-end scriptsubmitr_staging_demo.py: mimics submitr by pre-creating a staging file with mkstemp and passingallow_existing_staging_path=Truethrough aStructuredDataSetexcel_class✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.