Add the de-facto required methods to the IFileSystem Protocol - #10
Open
ninowalker wants to merge 1 commit into
Open
Add the de-facto required methods to the IFileSystem Protocol#10ninowalker wants to merge 1 commit into
ninowalker wants to merge 1 commit into
Conversation
cp, mv, link and lstat are called by the cp/mv/ln/readlink commands and the test builtin without a hasattr guard, so a backend implementing exactly the Protocol type-checks and then raises AttributeError at runtime. Declare them, with signatures matching all four built-in backends. Add a conformance test that reads the method list off the Protocol and checks every built-in backend implements it.
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.
IFileSystemdeclares 17 methods, but the commands call four more without ahasattrguard:lstatcommands/readlink/readlink.py:55,interpreter/builtins/test.py:381(test -L)cpcommands/cp/cp.py:136mvcommands/mv/mv.py:131linkcommands/ln/ln.py:112(lnwithout-s)So a backend that implements exactly the Protocol type-checks, passes a smoke test, and then raises
AttributeErrorthe first time a script runscp,mv,ln,readlink, ortest -L. Those call sites catch onlyOSErrorsubclasses, so it escapesbash.exec()as a Python exception rather than becoming a nonzero exit.I ran into it writing a custom backend over a remote store — I worked from the Protocol, everything looked complete, and
cpblew up at runtime.mypy already knew. On
main,mypy src/just_bash/reports exactly these:This PR removes all five (total goes 1003 -> 997).
The change
Four declarations added to
IFileSystem, signatures copied from the backends. All four ofInMemoryFs,ReadWriteFs,OverlayFsandMountableFsalready agree exactly on each one, so there was nothing to reconcile:No runtime behaviour changes — the Protocol is not
runtime_checkableand nothing subclasses it.Deliberately left out:
readdir_with_file_types. All four backends have it, butMountableFsguards it withhasattrand falls back toreaddir+stat, so it is genuinely optional and declaring it would make it mandatory for existing third-party backends. It also returnsDirentEntry, which lives infs/in_memory_fs.py, so declaring it would maketypes.pyimport fromfs/— which imports fromtypes.py. Same reasoning forget_all_paths, alsohasattr-guarded.The test
tests/test_fs/test_ifilesystem_conformance.pyreads the method list off the Protocol by introspection and asserts:IFileSystem12 cases, no fixtures. It would have caught #6 (
utimesmissing fromReadWriteFs) as well as this one.It does surface one pre-existing gap I have left alone:
realpathis declared onIFileSystembut onlyInMemoryFsimplements it, sopwd -Pandreadlink -fraiseAttributeErroron the other three backends. Rather than guess at the right semantics forOverlayFs(symlink handling there looks security-relevant) I listed it in a commentedKNOWN_GAPSset, so the test guards everything else without hiding it. Happy to send a separate PR for that, or fold it into this one if you would rather.One other thing worth knowing: CI runs
pytest tests/test_commands/ tests/test_network.py, sotests/test_fs/— this new file included — is not currently exercised there. I did not want to touch the workflow in this PR.Testing
pytest tests/test_commands/ tests/test_network.py(the CI command): 2314 passed, 1 skippedtests/spec_testsandtests/comparison_tests: 2925 passed, 3 skippedtests/spec_tests+tests/comparison_tests: identical results tomainFixes #8